【问题标题】:Nested Transactions in .NET.NET 中的嵌套事务
【发布时间】:2011-08-08 19:46:57
【问题描述】:

我怎样才能做到这一点? My understanding is that this is impossible with TransactionScopes 但我想以其他方式完成等效操作:

业务逻辑类:

public bool Bar()
{
  try
  {
    using (var tsWork = new TransactionScope())
    {
      ComplicatedDataImportCode(somedata);
      FlagRecordInDatabaseAsImported(); // this is the same record that's modified in the catch
      tsWork.Complete();
      return true;
    }
    catch (DuplicateDataException err)
    {
      // if we got here, the above transaction should have rolled back,
      // so take that same record in the database and update it to "Duplicate".
      FlagSameRecordInDatabaseAsDuplicate(err.Message);
    }

    return false;
}

现在一切正常,直到我将所有这些都封装在一个事务中(可能是我想在执行断言后回滚的集成测试)。

简单的测试来证明我的观点:

public void CanTest()
{
  // Arrange
  var foo = new Foo();

  using (var ts = new TransactionScope())
  {
    // Act
    var success = foo.Bar();

    // Assert
    if (success)
    {
      Assert.That(SomethingThatTestsThatTheDataWasImported);
    }
    else
    {
      Assert.That(SomethingThatTestsThatTheRecordWasMarkedAsDuplicate);
    }

    // Now that we have been able to perform our Asserts, rollback.

  }
}

最终,Foo.Bar() 中的代码可以修改以适应解决方案,但是 ComplicatedDataImportCode() 中的代码无法针对此解决方案进行修改,因此我真正需要的是确保在失败场景中正确回滚.

再次,根据我在本问题开头引用的帖子,我了解 TransactionScopes 不能用于执行此操作。我在这里使用 TransactionScopes 来表明我想要做什么,并且正在寻找实现此功能的最佳替代方法。

【问题讨论】:

    标签: .net .net-4.0 transactions sql-server-2008-r2


    【解决方案1】:

    是不是你使用的 DBMS 必须支持这一点?

    例如,SQL Server 并不真正支持嵌套事务,但是,对于 SQL Server,您可以使用 savepoints

    An article我几年前在我的博客上写过。

    【讨论】:

    • SQL Server 支持嵌套事务,只是第一个ROLLBACK 杀死了所有级别。 COMMIT 遵守嵌套。
    • 嗯,也许我误解了 SQL Server 支持这一点。我想了解更多。阅读您的链接。暂时 +1...
    • @Kratz:您的评论正是我的问题。我希望ROLLBACK 只回滚那个特定的“内部事务”而不是整个事情。
    • 我认为这确实是这个问题的答案。提出另一个问题,这次是关于 EF 和 Savepoints。 颤抖谢谢,弗雷德里克!
    • SQL Server 支持嵌套事务是一个常见的误解。它不是。打开多个事务然后调用 commit 绝对没有任何作用。您可以轻松编写一些测试 SQL 来自己尝试。此处模拟嵌套事务的唯一选择是使用上面提到的保存点。
    【解决方案2】:

    如果您可以获得ComplicatedDataImportCode 正在使用的活动数据库连接,您应该只需要在该连接上运行BEGIN TRANROLLBACK TRAN

    【讨论】:

    • 不过,这不允许部分回滚。回滚会破坏整个事务,这就是问题所在。所以如果我按照你说的做,那么当我执行回滚时,我对 FlagSameRecordInDatabaseAsDuplicate 的调用将不起作用,因为当我的 CanTest 方法调用它时它在同一个事务中。
    猜你喜欢
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 2016-09-09
    • 2014-12-12
    • 2016-09-10
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多