![](/img/trans.png)
[英]Difference between TransactionScope and Rollback Transaction manually?
[英]TransactionScope error in ambient transaction does not rollback the transaction
我使用這樣的環境事務:
using(TransactionScope tran = new TransactionScope()) {
CallAMethod1();//INSERT
CallAMethod2();//INSERT
tran.Complete();
}
方法CallAMethod2();
返回affected rows =-264
因此它無法插入,但是第一個插入已提交!
我想知道如何處理ambient transaction
,如果第二種方法有多個需要內部交易的動作,我應該將這些動作放入內部交易怎么辦? 像這樣 :
DAL_Helper.Begin_Transaction();
//------Fill newKeysDictioanry
affectedRow = DBUtilities.InsertEntityWithTrans("table2", newKeysDictioanry, DAL_Helper);
if (affectedRow == 1)
{
if (!string.IsNullOrEmpty(sp_confirm))
{
result_dt = UserTransactionDAL.Run_PostConfirm_SP(sp_PostConfirm, OBJ.ValuesKey, DAL_Helper);
if (result_dt.Rows.Count > 0 && result_dt.Rows[0][0].ToString() == "0")
{
DAL_Helper.current_trans.Commit();
if (DAL_Helper.connectionState == ConnectionState.Open)
{
DAL_Helper.Close_Connection();
}
return 1;// affectedRow;
}
else
{
DAL_Helper.current_trans.Rollback();
if (DAL_Helper.connectionState == ConnectionState.Open)
{
DAL_Helper.Close_Connection();
}
return -2;
}
}
//etc
1)您需要檢查tran.Complete();
叫做。 如果是tran.Complete();
調用后,TransactionScope被視為成功完成。
從MSDN
當您的應用程序完成它希望在事務中執行的所有工作時,您應該只調用一次Complete方法,以通知該事務管理器可以接受提交事務。 未能調用此方法將中止事務。
調用tran.Complete();
通知交易管理器完成交易。 實際上,事務管理器不會跟蹤您的Db適配器,也不知道連接中的操作是成功還是失敗。 您的應用程序必須通過調用Complete來告知它
要使交易失敗,只需確保不調用tran.Complete();
在您的代碼中:
如果事務范圍內(即,在TransactionScope對象的初始化與其調用Dispose方法之間)沒有發生異常,則允許該范圍所參與的事務繼續進行。 如果在事務范圍內確實發生異常,則其所參與的事務將被回滾。
就您而言,也許可以在CallAMethod2();
引發異常CallAMethod2();
如果您認為操作失敗,則tran.Complete();
不會被調用,並且事務將回滾。
2)您可以檢查的第二件事是您的連接是否已加入事務。 如果未征用連接,則TransactionScope不會回滾。 可能的問題是:
在這些情況下,您可以嘗試手動注冊連接(從上面的鏈接中提取):
connection.EnlistTransaction(Transaction.Current)
關於第二個問題:
如果第二種方法有多個需要內部事務的操作,該怎么辦呢?
我要說的是,這實際上取決於您是否考慮CallAMethod2();
作為葯自控操作,這意味着你可以在其他地方直接調用它沒有它包裹在一個事務中。 在大多數情況下,創建內部事務很有意義,因為可以嵌套事務。 在您的情況下,建議在CallAMethod2();
也使用TransactionScope CallAMethod2();
,在創建新的交易范圍時,我們有一些選擇:
TransactionScope類提供了幾個重載的構造函數,這些構造函數接受類型為TransactionScopeOption的枚舉,該枚舉定義了范圍的事務行為。 TransactionScope對象具有三個選項:
加入環境事務,如果不存在,則創建一個新事務。
成為新的根作用域,即啟動一個新事務,並使該事務成為其自身作用域內的新環境事務。
完全不參與交易。 結果,沒有環境交易。
哪種選擇真正取決於您的應用程序。 對於您的情況,我想您可以選擇第一種選擇。 以下是來自MSDN的示例
void RootMethod()
{
using(TransactionScope scope = new TransactionScope())
{
/* Perform transactional work here */
SomeMethod();
scope.Complete();
}
}
void SomeMethod()
{
using(TransactionScope scope = new TransactionScope())
{
/* Perform transactional work here */
scope.Complete();
}
}
您可以將作用域內部和外部用於事務:
string connectionString = ConfigurationManager.ConnectionStrings["db"].ConnectionString;
var option = new TransactionOptions
{
IsolationLevel = IsolationLevel.ReadCommitted,
Timeout = TimeSpan.FromSeconds(60)
};
using (var scopeOuter = new TransactionScope(TransactionScopeOption.Required, option))
{
using (var conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText="INSERT INTO Data(Code, FirstName)VALUES('A-100','Mr.A')";
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
}
using (var scopeInner = new TransactionScope(TransactionScopeOption.Required, option))
{
using (var conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText="INSERT INTO Data(Code, FirstName) VALUES('B-100','Mr.B')";
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
}
scopeInner.Complete();
}
scopeOuter.Complete();
}
閱讀Khanh TO所說的話。 如果您的連接是在外部事務范圍之外打開的,則不會征用該連接。
這就是為什么第二個失敗時第一個調用不回滾的原因。 您將必須征求您的聯系:
using (TransactionScope tran = new TransactionScope(TransactionScopeOption.Required))
{
connection.EnlistTransaction(Transaction.Current);
CallAMethod1();//INSERT
CallAMethod2();//INSERT
tran.Complete();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.