using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using SQLServerDAL.Web.DbBooking;
using SQLServerDAL.Web.AppInterface;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Model.Web.DbBooking;
namespace SQLServerDAL.Web
{
public class DbTansactionHelper : SQLServerBase
{
private static readonly Database DbSupermaket = DatabaseFactory.CreateDatabase("GtaConnectionString");
public bool BookReseverTran(ContactInfo contactInfo, CustomerInfo customerInfo, BookHotelInfo bookHotelInfo, BookInfo bookInfo)
{
bool successFalg = true;
DbConnection gtaConn = db.CreateConnection();
DbConnection supermarketConn = DbSupermaket.CreateConnection();
try
{
gtaConn.Open();
DbTransaction gtaTtransaction = gtaConn.BeginTransaction();//事務與conn中的cmd有關,但必須在一個conn中
successFalg &= this.GtaBookTran(contactInfo, customerInfo, bookHotelInfo, bookInfo, gtaTtransaction);
supermarketConn.Open();
DbTransaction supermarketTtransaction = supermarketConn.BeginTransaction();
successFalg &= this.SupermarketReseverTran(supermarketTtransaction);
if (successFalg)
{
supermarketTtransaction.Commit();
gtaTtransaction.Commit(); //達到分佈式的目的
}
else
{
supermarketTtransaction.Rollback();
gtaTtransaction.Rollback();
}
return successFalg;
}
finally
{
supermarketConn.Close();
gtaConn.Close();
}
}
public bool GtaBookTran(ContactInfo contactInfo, CustomerInfo customerInfo, BookHotelInfo bookHotelInfo, BookInfo bookInfo, DbTransaction transaction)
{
bool successFalg = true;
string hotelCustomeList;
string contactId;
string reseveId;
string hotelBookId;
Book book = new Book();
BookHotel bookHotel = new BookHotel();
Contact contact = new Contact();
Customer customer = new Customer();
//ReserveInterface reserveInterface = new ReserveInterface();
//插入到Contact表
successFalg &= contact.Insert(contactInfo, out contactId, transaction) > 0;
//插入到Customer表
successFalg &= customer.Insert(customerInfo, transaction) > 0;
//插入到BookHotel表
//傳入時需初始化
//bookHotelInfo.Customer=hotelCustomeList
//successFalg &= bookHotel.Insert(bookHotelInfo, transaction) > 0;
//初始化Book總表
//bookInfo.BookId = bookId;
//bookInfo.ContactId = contactId;
//bookInfo.ReserveId = reseveId;
successFalg &= book.Insert(bookInfo, transaction)>0;
return successFalg;
}
public bool SupermarketReseverTran(DbTransaction transaction)
{
//插入到訂單處理中心
//string webTypeAgentId = "cntocom";
//string webTypeDealer = "cxzhq2002";
//string webTypeMemberId = "cnto";
//LoginInfo loginInfo = new LoginInfo();
//string webTypeAgentId = loginInfo.AgentId;
//string webTypeDealer = loginInfo.Dealer;
//string webTypeMemberId = loginInfo.MemberId;
// successFalg = reserveInterface.ReserveHotel(bookInfo, bookHotelInfo, contactInfo, webTypeAgentId, webTypeDealer, webTypeMemberId, out reseveId);
//插入到Book總表
//bookInfo.ReserveId = reseveId;
//successFalg = book.Insert(bookInfo);
return true;
}
}
}
====================================
SqlTransaction 與 DbTransaction事務
System.Object
System.Data.Common.DbTransaction
System.Data.Odbc.OdbcTransaction
System.Data.OleDb.OleDbTransaction
System.Data.OracleClient.OracleTransaction
System.Data.SqlClient.SqlTransaction
System.Data.SqlServerCe.SqlCeTransaction
這是2.0的擴展類
在1.1中只實現了SqlTransaction .
代替類
bool successFalg = true;
using (TransactionScope insertTransaction = new TransactionScope())
{
string hotelCustomeList;
string contactId;
string reseveId;
string hotelBookId;
Book book = new Book();
BookHotel bookHotel = new BookHotel();
Contact contact = new Contact();
Customer customer = new Customer();
ReserveInterface reserveInterface = new ReserveInterface();
//插入到Contact表
ContactInfo contactInfo = this.InitContact();
successFalg &= contact.Insert(contactInfo, out contactId);
//插入到Customer表
ArrayList customerInfoList = this.InitCustomer(bookId, out hotelCustomeList);
successFalg &= customer.Insert(customerInfoList);
//插入到BookHotel表
BookHotelInfo bookHotelInfo = this.InitBookHotel(info, bookId, hotelCustomeList);
successFalg &= bookHotel.Insert(bookHotelInfo, out hotelBookId);
//初始化Book總表
BookInfo bookInfo = this.InitBook(bookId, hotelBookId, contactId, bookId, string.Empty);
//插入到訂單處理中心
string webTypeAgentId = "cntocom";
string webTypeDealer = "cxzhq2002";
string webTypeMemberId = "cnto";
//LoginInfo loginInfo = new LoginInfo();
//string webTypeAgentId = loginInfo.AgentId;
//string webTypeDealer = loginInfo.Dealer;
//string webTypeMemberId = loginInfo.MemberId;
successFalg &= reserveInterface.ReserveHotel(bookInfo, bookHotelInfo, contactInfo, webTypeAgentId, webTypeDealer, webTypeMemberId, out reseveId);
//插入到Book總表
bookInfo.ReserveId = reseveId;
successFalg = book.Insert(bookInfo);
if (successFalg)
{
insertTransaction.Complete();
}
}
return successFalg;
System.Transactions 是藉助的com+服務, 如果不行,則PlatformNotSupportedException。
,而DbTaansations是.net完全寫的,性能應該好點
System.Transactions 基礎結構既提供了基於 Transaction 類的顯式編程模型,也提供了使用 TransactionScope 類的隱式編程模型,在後一種模型中,事務由該基礎結構自動管理。
System.Transactions 基礎結構通過支持在 SQL Server、ADO.NET、MSMQ 和 Microsoft 分佈式事務協調器 (MSDTC) 中啓動的事務,使事務編程在整個平臺上變得簡單和高效。它提供基於 Transaction 類的顯式編程模型,還提供使用 TransactionScope 類的隱式編程模型,在這種模型中事務是由基礎結構自動管理的。強烈建議使用更爲方便的隱式模型進行開發。若要開始,請參見 主題。有關編寫事務性應用程序的更多信息,請參見 。
相對於完全用.net實現有SqlTransaction 與 DbTransaction事務, System.Transaction性能應該是差得,
但相關優化:另一個持久資源管理器向一個事務進行登記時,事務管理器還通過基於磁盤的事務管理器(如 DTC)進行協調,透明地將本地事務升級爲分佈式事務。System.Transactions 基礎結構提供增強性能的關鍵方式有兩種。
-
動態升級,即 System.Transactions 基礎結構只在事務實際需要 MSDTC 時才使用 MSDTC。這部分內容在 主題中詳細介紹。
-
可升級登記,如果某個資源是參與事務的唯一實體,則允許該資源(如數據庫)取得事務的所有權。以後,如果需要,System.Transactions 基礎結構仍然可以將事務管理交給 MSDTC。這樣進一步減少了使用 MSDTC 的機會。這部分內容在 主題中詳細介紹。
==================================
以下轉:
最近新搞了一臺服務器,打算把sqlserver服務從我的機器上移出去,也讓自己的機器輕鬆些,但在用到了事務處理時卻出現了錯誤。
然後就是一頓搜索與設置,終於總結一部解決方案,如有不妥之處懇請指正。
經常出的錯誤主要有以下三條:
一、該夥伴事務管理器已經禁止了它對遠程/網絡事務的支持;
二、在分佈式事務中登記時出錯;
三、事務被明的或暗的終止。
通常這三條錯誤是有前後關係的,所以以下這些設置,可能要大多都要設置一次。
解決方案如下:
一、這個問題是因爲你沒有啓用遠程/網絡事務。因爲Win2003默認是不安裝這個的。
安裝步驟如下:
1. 單擊“開始”,指向“控制面板”,然後單擊“添加/刪除程序”。
2. 單擊“添加/刪除 Windows 組件”。
3. 選擇“應用程序服務器”,然後單擊“詳細信息”。
4. 選擇“啓用網絡 DTC 訪問”,然後單擊“確定”。
5. 單擊“下一步”。
6. 單擊“完成”。
7. 停止分佈式事務協調器服務:“Distributed Transaction Coordinator”,然後重新予以啓動。
可以命令行執行:
net stop msdtc
net start msdtc
8. 停止參與分佈式事務的任何資源管理器服務(如 Microsoft SQL Server 或 Microsoft Message Queue Server),然後重新予以啓動。
二、
1、首先檢查兩臺機器的msdtc是否都已經打開了。如是不是,那就全都打開。
2、按如下步驟做設置:
a.點擊“開始”按鈕,指向管理工具,選擇"組件服務"。
b.展開"組件服務"樹,然後展開"我的電腦"。
c.右鍵單擊"我的電腦",然後選擇"屬性"。
d.在 MSDTC 選項卡中,點“安全配置”按鈕,
e.確保選中了下列選項:“網絡DTC訪問”與"XA事務"
f.另外,"DTC 登錄帳戶"一定要設置爲"NT Authority/NetworkService"。
3、單擊"確定"。這樣將會提示您"MS DTC 將會停止並重新啓動。
所有的依賴服務將被停止。請按'是'繼續"。單擊"是"繼續。
4、.單擊"確定"關閉"我的電腦"屬性窗口。
5、其他要說明的,在我的案例中沒有這些設置,因爲都已經滿足了
打開135端口、SQLServer至少打到sp3的補丁,現在已經有sp4了、如果是WIN2000,升級到SP4、升級MDAC到2.6以上,最好是2.8。
三、這個步驟其實應該在第二.2步中設置的:
組件服務—我的電腦—右鍵—屬性—MSDTC—安全配置—事務管理器通信不要求進行驗證,啓用XA事務
我用的是瑞星防火牆,要把安全級別設爲中級,否則還是有問題。
最後強調,如果不行請檢查兩臺機器的設置,不要只設置一臺。
補充一點:有一次新裝一臺機器,按上面的步驟設置了一個遍,還是出現“在分佈式事務中登記時出錯”的錯誤,簡直鬱悶到了極點,後來將那臺機器與 Sqlserver服務器放在同一個VLAN就一切OK了,原來是VLAN惹的禍,但是還是不明白爲什麼,可能是VLAN之間的路由規則過濾了什麼,還希望有明白人指點一下呀!呵呵!
================================
假如分佈式事務的客戶端和服務器端(可能N個)不在同一臺服務器上,如分別爲 Web服務器 和 Db 服務器,可能會出現以下兩個錯誤
1. 該夥伴事務管理器已經禁止了它對遠程/網絡事務的支持
通常這由安全配置引起的,對於 xp sp2/2k3+ ,默認可能關閉了遠程客戶端訪問 MSDTC,
如何配置見網友 小小螞蚱 圖文並茂的說明:
http://blog.csdn.net/bo310/archive/2007/08/30/1765728.aspx (找到最後一節“需要特別補充的是:”)
感謝 小小螞蚱
2. [COMException (0x8004d00e): 此事務已明地或暗地被確認或終止 (異常來自 HRESULT:0x8004D00E)]
昨天剛解決的此問題:
在數據庫服務器(MS SQL)上的 hosts 文件中加入 Web 服務器(IIS) 的 IP 和 主機名 映射對
a. 定位到 C:/WINDOWS/system32/drivers/etc 目錄
b. 記事本打開 hosts 文件(沒有擴展名)
c. 添加一行 Web 服務器 IP 和 主機名映射, 兩者以至少一個空格相隔, 如
10.10.1.118 MyWebServerHostName
d. Save,OK!
雖然問題,解決了,但是依然有疑惑:
爲何我使用 IP 連接還需要映射 HostName?後面參考 分佈式事務(一)——MTS設置 中提到“如果Server之間跨網段,則Server之間需要能互相PING到機器名(而不是IP地址)”,但是我的環境的的確確就是同一個局域網啊?
爲何 MSDTC 需要 HostName ?
此主題相關參考:
什麼是 hosts ?它有什麼作用?
http://baike.baidu.com/view/597330.htm
分佈式事務(一)——MTS設置
http://blog.csdn.net/honkerhero/archive/2007/03/28/1544072.aspx
TransactionScope異常:該夥伴事務管理器已經禁止了它對遠程/網絡事務的支持
http://www.cnblogs.com/crabo/archive/2007/05/17/750118.html
http://topic.csdn.net/t/20050609/20/4071871.html
webservice實現com+事務出現"此事務已明地或暗地被確認或終止"問題
收到 " 一個 A Microsoft 分佈式事務協調器問題阻止連接到配置數據庫 " 發佈程序集從 BizTalk Server 2004 時錯誤信息
http://support.microsoft.com/?kbid=839187
MSDTC 分佈式事務錯誤:[COMException (0x8004d00e): 此事務已明地或暗地被確認或終止 (異常來自 HRESULT:0x8004D00E)]
http://community.csdn.net/Expert/TopicView3.asp?id=5748153
DTCPing.exe 工具
http://download.microsoft.com/download/complus/msdtc/1.7/nt45/en-us/DTCPing.exe
=================================
1 SQL事務
sql事務是使用SQL server自身的事務:在存儲過程中直接使用Begin Tran,Rollback Tran,Commit Tran實現事務:
優點:執行效率最佳
限制:事務上下文僅在數據庫中調用,難以實現複雜的業務邏輯。
Demo:(所有demo,都以SQL Server自帶的Northwind數據的表Region爲例)
CREATE PROCEDURE dbo.SPTransaction
(
@UpdateID int,
@UpdateValue nchar(50),
@InsertID int,
@InsertValue nchar(50)
)
AS
begin Tran
Update Region Set RegionDescription=@UpdateValue where RegionID=@UpdateID
insert into Region Values (@InsertID,@InsertValue)
declare @RegionError int
select @RegionError=@@error
if(@RegionError=0)
COMMIT Tran
else
ROLLBACK Tran
GO
/**//// <summary>
/// SQL事務:
/// </summary>
public void SQLTran()
{
SqlConnection conn = new SqlConnection("Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password=123;");
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SPTransaction";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
conn.Open();
SqlParameter[] paras= new SqlParameter[]{
new SqlParameter ("@UpdateID",SqlDbType.Int,32),
new SqlParameter ("@UpdateValue",SqlDbType .NChar,50),
new SqlParameter ("@InsertID",SqlDbType.Int ,32),
new SqlParameter ("@InsertValue",SqlDbType.NChar ,50)};
paras[0].Value = "2";
paras[1].Value = "Update Value1";
paras[2].Value = "6";
paras[3].Value = "Insert Value1";
foreach (SqlParameter para in paras )
{
cmd.Parameters.Add(para);
}
cmd.ExecuteNonQuery();
}
2 ADO.net事務
Ado.net事務可能是大家一般都用的
優點:簡單,效率和數據庫事務差不多。
缺點:事務不能跨數據庫,只能在一個數據庫連接上。如果是兩個數據庫上就不能使用該事務了。
Demo:
/**//// <summary>
/// 一般的ADO.net 事務
/// </summary>
public void ADONetTran1()
{
SqlConnection conn = new SqlConnection("Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password=123;");
SqlCommand cmd = new SqlCommand();
try
{
cmd.CommandText = "Update Region Set RegionDescription=@UpdateValue where RegionID=@UpdateID";
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
conn.Open();
SqlParameter[] paras = new SqlParameter[]{
new SqlParameter ("@UpdateID",SqlDbType.Int,32),
new SqlParameter ("@UpdateValue",SqlDbType .NChar,50)};
paras[0].Value = "2";
paras[1].Value = "Update Value12";
foreach (SqlParameter para in paras)
{
cmd.Parameters.Add(para);
}
//開始事務
cmd.Transaction = conn.BeginTransaction();
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into Region values(@InsertID,@InsertValue)";
cmd.CommandType = CommandType.Text;
paras = new SqlParameter[]{
new SqlParameter ("@InsertID",SqlDbType.Int ,32),
new SqlParameter ("@InsertValue",SqlDbType.NChar ,50)};
paras[0].Value = "7";
paras[1].Value = "Insert Value";
cmd.Parameters.Clear();
foreach (SqlParameter para in paras)
{
cmd.Parameters.Add(para);
}
cmd.ExecuteNonQuery();
//提交事務
cmd.Transaction.Commit();
}
catch
{
//回滾事務
cmd.Transaction.Rollback();
throw;
}
finally
{
conn.Close();
}
}
TransactionScope事務類,它可以使代碼塊成爲事務性代碼。並自動提升爲分佈式事務
優點:實現簡單,同時能夠自動提升爲分佈式事務
Demo:
/**//// <summary>
/// TransactionScope事務:可自動提升事務爲完全分佈式事務的輕型(本地)事務。
/// 使用時要保證MSDTC服務(控制分佈事務)是開啓的可以使用:net start msdtc命令開啓服務;
/// </summary>
public void ADONetTran2()
{
SqlConnection conn = new SqlConnection("Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password=123;");
SqlCommand cmd = new SqlCommand();
try
{
using (System.Transactions.TransactionScope ts = new TransactionScope())
{
cmd.CommandText = "Update Region Set RegionDescription=@UpdateValue where RegionID=@UpdateID";
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
conn.Open();
SqlParameter[] paras = new SqlParameter[]{
new SqlParameter ("@UpdateID",SqlDbType.Int,32),
new SqlParameter ("@UpdateValue",SqlDbType .NChar,50)};
paras[0].Value = "2";
paras[1].Value = "Update Value12";
foreach (SqlParameter para in paras)
{
cmd.Parameters.Add(para);
}
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into Region values(@InsertID,@InsertValue)";
cmd.CommandType = CommandType.Text;
paras = new SqlParameter[]{
new SqlParameter ("@InsertID",SqlDbType.Int ,32),
new SqlParameter ("@InsertValue",SqlDbType.NChar ,50)};
paras[0].Value = "8";
paras[1].Value = "Insert Value";
cmd.Parameters.Clear();
foreach (SqlParameter para in paras)
{
cmd.Parameters.Add(para);
}
cmd.ExecuteNonQuery();
//提交事務
ts.Complete();
}
}
catch
{
throw;
}
finally
{
conn.Close();
}
}
在分佈式應用程序中,往往要同時操作多個數據庫,使用數據庫事務就不能滿足業務的要求了。在COM+中,提供完整的事務處理服務。很方便處理多個數據庫上的事務。
Demo:
/**//// <summary>
/// COM+事務
/// </summary>
public void ComTran()
{
SqlConnection conn = new SqlConnection("Data Source=127.0.0.1;Initial Catalog=Northwind;Persist Security Info=True;User ID=sa;Password=123;");
SqlCommand cmd = new SqlCommand();
ServiceConfig sc = new ServiceConfig();
//指定事務類型
sc.Transaction = TransactionOption.Required;
//設置啓動跟蹤
sc.TrackingEnabled = true;
//創建一個上下文,該上下文的配置由作爲 cfg 參數傳遞的 ServiceConfig 對象來指定。
//隨後,客戶端和服務器端的策略均被觸發,如同發生了一個方法調用。
//接着,新的上下文被推至上下文堆棧,成爲當前上下文
ServiceDomain.Enter(sc);
try
{
cmd.CommandText = "Update Region Set RegionDescription=@UpdateValue where RegionID=@UpdateID";
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
conn.Open();
SqlParameter[] paras = new SqlParameter[]{
new SqlParameter ("@UpdateID",SqlDbType.Int,32),
new SqlParameter ("@UpdateValue",SqlDbType .NChar,50)};
paras[0].Value = "2";
paras[1].Value = "Update Value22";
foreach (SqlParameter para in paras)
{
cmd.Parameters.Add(para);
}
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into Region values(@InsertID,@InsertValue)";
cmd.CommandType = CommandType.Text;
paras = new SqlParameter[]{
new SqlParameter ("@InsertID",SqlDbType.Int ,32),
new SqlParameter ("@InsertValue",SqlDbType.NChar ,50)};
paras[0].Value = "9";
paras[1].Value = "Insert Value";
cmd.Parameters.Clear();
foreach (SqlParameter para in paras)
{
cmd.Parameters.Add(para);
}
cmd.ExecuteNonQuery();
//提交事務
ContextUtil.SetComplete();
}
catch
{
//回滾事務
ContextUtil.SetAbort();
throw;
}
finally
{
conn.Close();
//觸發服務器端的策略,隨後觸發客戶端的策略,如同一個方法調用正在返回。
//然後,當前上下文被彈出上下文堆棧,調用 Enter 時正在運行的上下文成爲當前的上下文。
ServiceDomain.Leave();
}
}
在.net中還有些也能進行事務處理,如web Service中
需要特別補充的是:
如果你使用的是分佈事務(TransactionScope事務和COM+事務),在默認情況下你是要重新配置安裝SQL Server數據庫服務器和訪問數據庫的客戶端的.(如果沒有配置運行會出現以下錯誤:該夥伴事務管理器已經禁止了它對遠程/網絡事務的支持。 (異常來自 HRESULT:0x8004D025)
)下面是MSDN上關於配置分佈式事務的一段原話:
配置分佈式事務
要啓用分佈式事務,可能需要通過網絡啓用 MS DTC,以便在使用應用了最新的 Service Pack 的較新操作系統(例如 Windows XP 或 Windows 2003)時使用分佈式事務。如果啓用了 Windows 防火牆(Windows XP Service Pack 2 的默認設置),必須允許 MS DTC 服務使用網絡或打開 MS DTC 端口。
實際怎麼配置呢,經過我的實際使用:大致如下: 打開'控制面板'->'管理工具'->'組件服務',點開'組件服務'->'計算機'->'我的電腦',在'我的電腦'上右擊屬性,點'MSDTC',然後點'安全性配置'。作爲數據庫的服務器的配置如下:
而訪問數據庫的客戶端的配置和服務器端的稍有些差別:
在設置完上面的還有使防火牆MS DTC 服務使用網絡或打開 MS DTC 端口:運行netsh firewall set allowedprogram %windir%/system32/msdtc.exe MSDTC enable命令就可以了