簡體   English   中英

環境事務中的TransactionScope錯誤不會回滾該事務

[英]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來告知它

TransactionScope如何回滾事務?

要使交易失敗,只需確保不調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM