我正在尝试制作一个快速的虚拟应用程序,以便了解 System.Transactions 的来龙去脉。这个应用程序与 2 个不同的 SQLExpress DB 交互。如果我在组件服务中提取我的事务统计信息,我可以看到在打开第二个连接时在 outerScope 中启动了一个事务。如果 failOuter 为真,则事务中止,但不会引发任何异常。当 failInner 为真时,会抛出 TransactionAbortedException。
来自 MSDN:
当您的应用程序完成它想要在事务中执行的所有工作时,您应该只调用一次 Complete 方法来通知事务管理器可以接受提交事务。将 Complete 调用作为 using 块中的最后一条语句是非常好的做法。
未能调用此方法会中止事务,因为事务管理器将此解释为系统故障,或等效于事务范围内抛出的异常。
如果作用域创建事务并且事务被中止,则会引发 TransactionAbortedException。
基于此,我希望我的 outerScope 会抛出 TransactionAbortedException,因为每次我运行我的应用程序并将 failOuter 设置为 true 时,我的事务统计信息都会显示一个中止的事务。我的方法返回 true,因为即使事务中止也不会引发异常。除非我中止内部事务,否则它的行为与我预期的一样。任何澄清将不胜感激。
public bool CreateNestedTransaction(bool failOuter, bool failInner)
{
try
{
using (TransactionScope outerScope = new TransactionScope())
{
/* Perform transactional work here */
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
myCommand.ExecuteNonQuery();
}
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test1"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = Value";
myCommand.ExecuteNonQuery();
}
using (TransactionScope innerScope = new TransactionScope())
{
using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=test2"))
{
SqlCommand myCommand = new SqlCommand();
myConnection.Open();
myCommand.Connection = myConnection;
myCommand.CommandText = "update test set Value = ((select Value from test where Id = (select max(Id) from test))+1) where Id = (select max(Id) from test)";
myCommand.ExecuteNonQuery();
}
if (failInner == false) { innerScope.Complete(); }
}
if (failOuter == false) { outerScope.Complete(); }
}
}
catch (TransactionAbortedException)
{
return false;
}
return true;
}