我使用这样的环境交易:
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
答案 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();
}