直到明确完成,事务范围(TransactionScope)是否隐式应用?

5
请考虑以下方法。
DoA()
{
  using (TransactionScope scope = new TransactionScope)
  {
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      connection.Open();
      SqlCommand command = new SqlCommand(query, connection);
      command.ExecuteNonReader();

      DoB();    

      scope.Complete();
    }
  }
}

DoB()
{
  using (TransactionScope scope = new TransactionScope)
  {
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      connection.Open();
      SqlCommand command = new SqlCommand(query, connection);
      command.ExecuteNonReader();

      DoC();

      scope.Complete();
    }
  }
}

DoC()
{
  using (SqlConnection connection = new SqlConnection(connectionString))
  {
    connection.Open();
    SqlCommand command = new SqlCommand(query, connection);
    command.ExecuteNonReader();
  }
}

如果我们调用DoA(),那么在SQL Server中,DoB()DoC()的后续交互是否在DoA()的事务上下文中运行?DoC()是否在DoA()DoB()的事务上下文中都运行?
(或者我是否严重误解了什么?)

1
你可以获得嵌套事务 :) - DaveShaw
有一些选项可以控制这个。请参阅http://msdn.microsoft.com/en-us/library/ms172152(v=vs.85).aspx中的“使用TransactionScopeOption管理事务流程”。 - AaronLS
@DaveShaw,我很难完全理解这个问题,因为它与我在其他语言中的事务管理实践大不相同。可以这样说DoC()的工作是在DoB()的事务块中运行吗?(而DoB()又嵌套在DoA()的事务中。) - svidgen
我认为这是描述它的准确方式。它类似于SQL Server中嵌套事务的工作方式。思路是,如果DoC支持事务,则DoB可以执行一些操作,并要求(这些操作)+ DoC()全部成功或全部失败。这使您能够构建自己的具有事务感知功能的方法,甚至DoB可能是对某个其他事务感知文档服务器的调用,在其中添加文档,但还将记录插入到SQL Server中,并要求两个操作参与同一个事务。 - AaronLS
1
@svidgen 哦,我明白了。我对 DbTransactions 不是很熟悉,但看起来这里的答案可能会解决这个问题:https://dev59.com/pljUa4cB1Zd3GeqPNQa9 - AaronLS
显示剩余4条评论
2个回答

5
所有的代码逻辑上都将成为一个单一的事务。嵌套作用域不一定会创建新的事务(除非使用RequiresNew),因此它将是一个单一的事务。现在,每个作用域必须投票以完成事务,因此如果您在第二个作用域中删除Complete,应该会导致整个事务回滚。
DoC也将成为事务的一部分;环境事务将检测到新连接并自动注册。
请阅读这里的所有细节,其中解释了注册环境事务和不同选项RequiresRequiresNewSuppress的行为。
还要注意,如果您的连接字符串不完全相同,这将自动将整个事务升级为分布式事务。这只是需要注意的一些事情。

+1 很好的信息。在我接受之前,您能否确认 DoC() 是在 DoA() 和/或 DoB() 的环境事务中执行的?(这是我期望认为会发生的 - 但想要确保。) - svidgen

2

根据Andy的评论进行了编辑:

似乎在SQL服务器上会发生这样的情况:

BEGIN TRANSACTION A

  -- do A's work

  -- B does NOT create a new transaction

    -- do B's work

    -- do C's work

COMMIT TRANSACTION A

如果在 DoB() 中使用 new TransactionScope(TransactionScopeOption.RequiresNew),则会发生以下情况。
BEGIN TRANSACTION A

  -- do A's work

  BEING TRANSACTION B

    -- do B's work

    -- do C's work

  COMMIT TRANSACTION B
COMMIT TRANSACTION A

这不是将会发生的事情;它将作为一个单一的事务,因为在 B 中使用的范围将加入现有的环境事务。如果 B 不投票以“完成”整个事务,则将回滚。 - Andy
@Andy 感谢您的澄清。如果使用 new TransactionScope(TransactionScopeOptions.RequiresNew),会发生这种情况吗? - svidgen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接