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

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

问题描述

我使用这样的环境事务:

I use an ambient transaction like this :

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

方法CallAMethod2();返回受影响的行=-264所以它无法插入但是第一个插入已经提交!

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) 需要检查 tran.Complete(); 是否被调用.如果调用 tran.Complete();,则认为 TransactionScope 已成功完成.

1) You need to check whether the tran.Complete(); is called. If the tran.Complete(); is called, the TransactionScope is considered completed successfully.

来自 MSDN

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

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.

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

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

TransactionScope 如何回滚事务?

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

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

如果事务范围内(即在TransactionScope 对象的初始化和调用它的 Dispose 方法),然后是作用域所在的事务允许参与.如果异常确实发生在交易范围,它参与的交易将被回滚.

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.

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

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) 您可以检查的第二件事是您的连接是否已登记在交易中.如果未登记连接,TransactionScope 不会回滚.可能的问题是:

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:

  • 如果连接在进入事务范围之前存在,则不会登记: TransactionScope 是否适用于预先存在的连接?
  • 您的基础连接不支持自动登记.

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

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

connection.EnlistTransaction(Transaction.Current)

关于你的第二个问题:

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

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

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

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:

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

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.

选择哪一个实际上取决于您的应用程序.在您的情况下,我想您可以选择第一个选项.下面是 MSDN

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 错误不会回滚事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!

上一篇:在 C# 和 Windows 中写入事务性文件? 下一篇:涉及多个表的多个事务的无间隙序列

相关文章

最新文章