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

时间:2015-01-28 11:38:39

标签: c# asp.net transactions informix transactionscope

我使用这样的环境交易:


using(TransactionScope tran = new TransactionScope()) {
    CallAMethod1();//INSERT
    CallAMethod2();//INSERT
    tran.Complete();
}

方法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

3 个答案:

答案 0 :(得分:5)

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

来自MSDN

  

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

tran.Complete();的调用是通知事务管理器完成交易。实际上,事务管理器不跟踪您的Db适配器,也不知道连接中的操作是成功还是失败。您的申请必须通过致电Complete

告知

How does TransactionScope roll back transactions?

要使您的交易失败,请确保您不要在代码中致电tran.Complete();

  

如果事务范围内没有异常(即介于两者之间)   TransactionScope对象的初始化和调用   它的Dispose方法),然后是范围内的事务   参与者被允许继续。如果在其中发生异常   交易范围,它参与的交易将   回滚。

在您的情况下,如果您认为操作失败,那么您可以在CallAMethod2();中抛出异常,以便tran.Complete(); 被调用并且事务被回滚

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

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

connection.EnlistTransaction(Transaction.Current)

关于你的第二个问题:

  

如果第二种方法有多个需要内部的动作,该怎么办?   交易,我应该把这些行动放在内部交易中吗?

我想说这实际上取决于您是否将CallAMethod2();视为 automic 操作,这意味着您可以直接在其他地方调用它而不将其包含在事务中。大多数情况下,创建内部事务是有意义的,因为事务可以嵌套。在您的情况下,建议您在CallAMethod2();中使用TransactionScope,我们在创建新的交易范围时有一些选择:

  

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();
     }
}

答案 1 :(得分:2)

您可以使用范围内部和外部进行交易:

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();
}

答案 2 :(得分:1)

阅读Khanh TO所说的话。如果您的连接在外部事务范围之外打开,则不会登记连接。

这就是第二次失败时第一次调用没有回滚的原因。您必须登记您的连接:

using (TransactionScope tran = new TransactionScope(TransactionScopeOption.Required))
{
   connection.EnlistTransaction(Transaction.Current);
   CallAMethod1();//INSERT
   CallAMethod2();//INSERT
   tran.Complete();
}
相关问题