【问题标题】:Why doesn't TransactionScope assume success?为什么 TransactionScope 不假定成功?
【发布时间】:2010-01-04 13:15:24
【问题描述】:

TransactionScope 期望调用其 Complete 方法,如下所示。否则不会提交事务。

using(TransactionScope scope = new TransactionScope())
{
    /* Perform transactional work here */

    scope.Complete();
}

假设成功的实现不是更合适吗?这意味着在标准情况下需要更少的代码(成功)。

如果发生异常或调用诸如“回滚”之类的方法(此方法当前不存在),事务可能会回滚。

using(TransactionScope scope = new TransactionScope())
{
    /* Perform transactional work here */

     if(problemOccurred)
     {
         scope.Rollback();
     }
}

请注意,problemOccurred 标志仅在问题未导致异常的情况下才需要。在这种情况下,将自动执行回滚。

我有兴趣进一步了解为什么使用此实现。

更新:到目前为止,一些答案认为如果使用我描述的实现,则需要一个 try-catch 块。不是这种情况。当使用块中未处理异常时,事务会自动回滚。现有实现和我描述的实现都是这种情况。有关详细信息,请参阅“完成事务范围”部分 here

更新 2: 我终于明白答案中的解释了。这不是一种语言结构,可以以任何语言设计者认为合适的方式解释 - 它是 IDisposable 模式的实现。如果没有调用 Complete,Dispose 方法中的代码将不知道调用它是因为 using 块中的代码成功执行还是因为发生了异常。我在想像下面这样的东西,其中事务和回滚都是关键字。

transaction
{
    /* Perform transactional work here */

     if(problemOccurred)
     {
         rollback;
     }
}

如果需要将事务选项传递给 TransactionScope,这当然会出现问题。

【问题讨论】:

  • 为什么我换页时没有自动添加评论,我不应该点击[添加评论]...
  • From update - 在遇到异常时回滚事务的机制是您在没有调用 Commit 的情况下到达 using 块的末尾。 IE。该行为取决于您要删除的确切功能。
  • 您的更新是错误的 - 它当前回滚的唯一原因是正是您所抱怨的行为。它假设失败 - 如果发生异常,Complete() 永远不会被调用,因此事务失败。没有其他神奇的机制可以捕捉异常。
  • @Scott - 尝试自己实现这个 - 你所要做的就是实现一个实现 IDisposable 的类,并且在 Dispose 方法中,你必须确定你是否因为一个异常被传播 - 你会意识到为什么它不起作用。
  • 谢谢达米安。我认为 TransactionScope 是一种语言结构,可以按照语言设计者决定的任何方式进行解释,但它只不过是 IDisposable 的实现。

标签: .net transactionscope


【解决方案1】:

这样,每笔交易都将如下所示:

using(TransactionScope scope = new TransactionScope())
{
  try
  {
    /* Perform transactional work here */
  }
  catch (Exception)
  {
    scope.Rollback();
    throw;
  }
}

哪个是更多的代码。

编辑:

其他一切都是有风险的或糟糕的风格。 您必须绝对确定提交时没有任何错误。离开 using 块时,您不知道是因为抛出异常还是因为您刚刚到达它的末尾而离开它。打电话给Complete就知道了。

事务块语法已经是你能做的最简单的了。只需在没有任何特殊错误处理的情况下实现事务并在最后提交。当发生任何错误时,您不必关心和回滚。考虑一下,几乎每一行代码都可能引发异常(例如 NullReference、溢出、InvalidOperation 等)。那么还有什么比这更容易的呢?

【讨论】:

  • 如果使用 scope.Complete() 方法,如果有必要,何时会发生回滚?
  • TransactionScope 的 using 块中的异常会自动回滚事务。这里是 MSDN 的一个例外。 “未能调用此方法会中止事务,因为事务管理器将此解释为系统故障,或等效于事务范围内抛出的异常。”你的 try 块是多余的。
  • 这个答案是自动Complete()ing TransactionScope 的假设说明。 Microsoft 评论仅适用于非自动Complete()ing 版本,即当前版本。
  • @Scott - 这需要在 CLR 内部进行更改才能实现 - 您需要一些神奇的新方法来拦截未处理的异常
【解决方案2】:

这意味着您不需要为失败情况放置手动 try/finally(或 catch)块(可能带有“成功”标志)。尝试重写上面的代码以回滚错误,看看它有多混乱......

基本上,正常的期望行为是仅在到达块末尾时才提交,没有例外。实现这一目标的最简单方法是在块的末尾放置一个表示成功的方法调用。

【讨论】:

  • 我认为不需要 try 块 - 请参阅我在回答中的评论...stackoverflow.com/questions/1999461/…你同意吗?
  • 不,因为你提议改变这种行为。 目前由于您所抱怨的行为,您不需要 try/catch 块 - 除非您明确提交,否则假定失败。
【解决方案3】:

如果选择了其他实现,那么人们会问相反的问题!

说真的,旨在防止部分或不正确更新的机制中的默认行为肯定必须提交,不是吗?

【讨论】:

    【解决方案4】:

    我认为,正如@Jon Skeet 所说,为成功而编写的代码量更少(也更少丑陋)当前的方式。但是,从事务的角度来看,我认为您会想要悲观并假设除非明确表明成功,否则您会回滚。在我看来,错误提交事务比由于代码错误而意外未能成功提交事务要糟糕得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-22
      • 2015-01-13
      • 2019-04-24
      • 2017-12-10
      • 1970-01-01
      • 2023-03-23
      • 2013-10-17
      • 2021-06-14
      相关资源
      最近更新 更多