环境事务中的TransactionScope错误不会回滚事务

Any*_*are 1 c# asp.net informix transactions transactionscope

我使用这样的环境事务:


using(TransactionScope tran = new TransactionScope()) {
    CallAMethod1();//INSERT
    CallAMethod2();//INSERT
    tran.Complete();
}
Run Code Online (Sandbox Code Playgroud)

该方法CallAMethod2();返回affected rows =-264 所以它无法插入但是第一个Insert已经提交了!

我想知道如何使用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
Run Code Online (Sandbox Code Playgroud)

Kha*_* TO 5

1)你需要检查是否tran.Complete();被调用.如果tran.Complete();调用,则认为TransactionScope已成功完成.

来自MSDN

当您的应用程序完成它想要在事务中执行的所有工作时,您应该只调用一次Complete方法,以通知该事务管理器提交事务是可以接受的.未能调用此方法将中止事务.

调用tran.Complete();是通知事务管理器完成事务.实际上,事务管理器不跟踪您的Db适配器,也不知道连接中的操作是成功还是失败.您的应用程序必须通过调用Complete来告知它

TransactionScope如何回滚交易?

要使您的交易失败,只需确保不要调用tran.Complete();您的代码:

如果事务范围内没有发生异常(即,在TransactionScope对象的初始化和调用其Dispose方法之间),则允许进行范围参与的事务.如果事务范围内确实发生了异常,则将回滚它参与的事务.

在你的情况,也许你可以扔在你的一个例外CallAMethod2();,如果你认为操作失败,因此tran.Complete();叫,事务回滚.

2)您可以检查的第二件事是您的连接是否已在事务中登记.如果未登记连接,则TransactionScope不会回滚.可能的问题是:

在这些情况下,您可以尝试手动登记您的连接(从上面的链接中提取):

connection.EnlistTransaction(Transaction.Current)
Run Code Online (Sandbox Code Playgroud)

关于你的第二个问题:

如果第二种方法有多个需要内部事务的操作,我应该将这些操作放在内部事务中怎么办?

我会说这真的取决于你是否认为你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();
     }
}
Run Code Online (Sandbox Code Playgroud)