TransactionScope的错误在环境事务不会回滚事务 [英] TransactionScope error in ambient transaction does not rollback the transaction

查看:253
本文介绍了TransactionScope的错误在环境事务不会回滚事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用一个环境事务是这样的:


 使用(TransactionScope的TRAN =新的TransactionScope()){
    CallAMethod1(); //插入
    CallAMethod2(); //插入
    tran.Complete();
}

该方法 CallAMethod2(); 收益受影响的行= -264
因此,无法插入,然而前将一直致力于!

我想知道如何使用环境事务,如果第二个方法有一个以上的行动,需要内部交易什么工作,我应该把这些动作在内部交易?
像这样的:

  DAL_Helper.Begin_Transaction();              // ------填写newKeysDictioanry                affectedRow = DBUtilities.InsertEntityWithTrans(表2,newKeysDictioanry,DAL_Helper);                如果(affectedRow == 1)
                {
                    如果(!string.IsNullOrEmpty(sp_confirm))
                    {
                        result_dt = UserTransactionDAL.Run_PostConfirm_SP(sp_PostConfirm,OBJ.Values​​Key,DAL_Helper);
                        如果(result_dt.Rows.Count大于0&放大器;&放大器; result_dt.Rows [0] [0]的ToString()==0)
                        {
                            DAL_Helper.current_trans.Commit();                            如果(DAL_Helper.connectionState == ConnectionState.Open)
                            {
                                DAL_Helper.Close_Connection();
                            }
                            返回1; // affectedRow;
                        }
                        其他
                        {
                            DAL_Helper.current_trans.Rollback();
                            如果(DAL_Helper.connectionState == ConnectionState.Open)
                            {
                                DAL_Helper.Close_Connection();
                            }
                            返回-2;
                        }
                    }
//等等


解决方案

1)你必须检查是否 tran.Complete(); 被调用。如果 tran.Complete(); 被调用时,的TransactionScope被视为成功完成。

MSDN


  

当您的应用程序完成所有工作,它希望在执行
  交易,你应该调用完整的方法只有一次通知
  该事务管理器,它是可以接受的,以提交
  交易。如果不调用此方法中止交易。


tran.Complete()的调用; 是通知事务管理器来完成交易。事实上,事务管理器不会跟踪你的数据库适配器和不知道的话,连接操作是成功还是失败。您的应用程序,让它知道通过调用<一个href=\"https://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.complete(v=vs.110).aspx\"相对=nofollow>完整

<一个href=\"http://stackoverflow.com/questions/494550/how-does-transactionscope-roll-back-transactions\">How确实的TransactionScope回滚事务?

要失败的事务,只是确保你不叫 tran.Complete(); 在code:


  

如果事务范围内没有发生异常(即,之间
  所述的TransactionScope对象的初始化和主叫
  其Dispose方法),那么该交易在该范围
  参与被允许继续进行。如果一个例外情况中发生
  交易范围,交易它所参与的意愿
  被回滚。


如果你觉得操作失败,让 tran.Complete;

在你的情况,也许你可以在你的 CallAMethod2()抛出一个异常(); 不可以调用,事务回滚

2),您可以检查的第二件事是在交易中你的连接是否登记。如果连接未被征集的TransactionScope不回滚。可能的问题是:


  • 如果进入交易范围之前,连接存在,它不会征召:<一href=\"http://stackoverflow.com/questions/9257907/does-transactionscope-work-with-$p$p-existing-connections\">Does以pre-现有连接TransactionScope的工作?

  • 您的基础连接不支持自动登记。

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

  connection.EnlistTransaction(Transaction.Current)

关于你提到的第二个问题:


  

如果第二个方法有一个以上的行动这就需要内部
  交易,我应该把这些动作在内部交易?


我会说这真的取决于你是否认为你的 CallAMethod2(); 药自控运行,这意味着你可以在其他地方直接叫它没有包装它在事务内。大多数情况下,这将是有意义的创建内部交易的交易可以嵌套。根据你的情况,建议在同时使用的TransactionScope你的 CallAMethod2(); ,我们有一些选择创建一个新的事务范围时:


  

TransactionScope类提供了几个构造函数重载
  接受类型TransactionScopeOption,枚举其中
  定义范围的事务行为。一个TransactionScope
  对象有三个选项:


  
  

加入环境事务,或者如果不存在创建一个新的。


  
  

是一个新的根范围内,即启动一个新的事务,并让该交易将自己的范围内新的环境事务。


  
  

不参与交易的。没有环境事务作为结果


选择哪一个取决于你的应用程序。在你的情况,我想你可以用第一个选项去。下面是 MSDN

 无效RootMethod()
{
     使用(TransactionScope的范围=新的TransactionScope())
     {
          / *在这里执行的事务性工作* /
          的someMethod();
          scope.Complete();
     }
}无效的someMethod()
{
     使用(TransactionScope的范围=新的TransactionScope())
     {
          / *在这里执行的事务性工作* /
          scope.Complete();
     }
}

I use an ambient transaction like this :


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

The method CallAMethod2(); returns affected rows =-264 So it fails to insert however the first Insert has been committed !

I want to know how to work with ambient transaction and what if the second method has more than one action which needs internal transaction , should i put these actions in internal transaction ? like this :

     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) You need to check whether the tran.Complete(); is called. If the tran.Complete(); is called, the TransactionScope is considered completed successfully.

From MSDN

When your application completes all work it wants to perform in a transaction, you should call the Complete method only once to inform that transaction manager that it is acceptable to commit the transaction. Failing to call this method aborts the transaction.

The call to tran.Complete(); is to inform the Transaction Manager to complete the transaction. Actually, the Transaction Manager does not track your Db adapter and does not know if an operation in a connection was successful or failed. Your application has to let it know by calling Complete

How does TransactionScope roll back transactions?

To fail your transaction, just ensure that you don't call tran.Complete(); in your code:

If no exception occurs within the transaction scope (that is, between the initialization of the TransactionScope object and the calling of its Dispose method), then the transaction in which the scope participates is allowed to proceed. If an exception does occur within the transaction scope, the transaction in which it participates will be rolled back.

In your case, maybe you can throw an exception in your CallAMethod2(); if you think the operation has failed so the tran.Complete(); is not called and the transaction is rolled back.

2) The second thing you can check is whether your connection is enlisted in the transaction. TransactionScope does not rollback if the connection is not enlisted. The possible problems are:

In these cases, you can try enlisting your connection manually (extracted from the link above):

connection.EnlistTransaction(Transaction.Current)

Regarding your second question:

what if the second method has more than one action which need internal transaction , should i put these actions in internal transaction ?

I would say it really depends on whether you consider your CallAMethod2(); as an automic operation which means you can call it elsewhere directly without wrapping it inside a transaction. Most of the cases, it would make sense to create internal transactions as transactions can be nested. In your case, it's recommended to also use TransactionScope in your CallAMethod2();, we have some options when creating a new transaction scope:

The TransactionScope class provides several overloaded constructors that accept an enumeration of the type TransactionScopeOption, which defines the transactional behavior of the scope. A TransactionScope object has three options:

Join the ambient transaction, or create a new one if one does not exist.

Be a new root scope, that is, start a new transaction and have that transaction be the new ambient transaction inside its own scope.

Not take part in a transaction at all. There is no ambient transaction as a result.

Which one to choose really depends on your application. In your case, I guess you could go with the first option. Below is an example from 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();
     }
}

这篇关于TransactionScope的错误在环境事务不会回滚事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆