TransactionScope的错误在环境事务不会回滚事务 [英] TransactionScope error in ambient transaction does not rollback the transaction
问题描述
我使用一个环境事务是这样的:
使用(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.ValuesKey,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被视为成功完成。
当您的应用程序完成所有工作,它希望在执行
交易,你应该调用完整的方法只有一次通知
该事务管理器,它是可以接受的,以提交
交易。如果不调用此方法中止交易。
块引用>到
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 为例p>
无效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();
returnsaffected 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 thetran.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 CompleteHow 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 thetran.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:
- If the connection exists before entering the transaction scope, it won't enlist: Does TransactionScope work with pre-existing connections?
- Your underlying connection does not support auto enlistment.
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 yourCallAMethod2();
, 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屋!