为什么 TransactionScope 不假设成功?

发布于 2024-08-16 17:27:08 字数 1215 浏览 6 评论 0原文

TransactionScope 期望按如下方式调用其 Complete 方法。否则交易将不会被提交。

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

    scope.Complete();
}

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

如果出现异常或调用“Rollback”等方法(此方法当前不存在),则可以回滚事务。

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

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

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

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

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

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

transaction
{
    /* Perform transactional work here */

     if(problemOccurred)
     {
         rollback;
     }
}

如果事务选项需要传递到 TransactionScope,这当然会带来问题。

The TransactionScope expects a call to its Complete method as follows. Otherwise the transaction will not be committed.

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

    scope.Complete();
}

Wouldn't an implementation that assumes success have been more appropriate? This would mean that less code would be required in the standard case (success).

In the case of an exception or a call to a method such as 'Rollback' (this method does not currently exist) the transaction could be rolled back.

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

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

Note that the problemOccurred flag would only be required in cases where the problem did not result in an exception. In this case, the rollback would be performed automatically.

I am interested in gaining further insight into why this implementation was used.

Update: A couple of the answers so far argued that a try-catch block would be required if the implementation that I described were used. This is not the case. The transaction is automatically rolled back when an exception is not handled within the using block. This is the case in both the existing implementation and the one that I described. See 'Completing a transaction scope' section here for further details.

Update 2: I finally understand what was being explained in the answers. This is not a language construct that could have been interpreted any way that the language designers saw fit - it is an implementation of the IDisposable pattern. Without the call to Complete the code within the Dispose method would have no knowledge of whether it is being called as the result of the code within the using block being executed successfully or because an exception occurred. I was imagining something similar to the following where both transaction and rollback are keywords.

transaction
{
    /* Perform transactional work here */

     if(problemOccurred)
     {
         rollback;
     }
}

This would of course present problems if transaction options need to be passed to the TransactionScope.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

手心的温暖 2024-08-23 17:27:08

这样,每笔交易都会看起来像这样:

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

哪个是更多代码。

编辑:

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

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

This way, every transaction would look like this:

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

Which is more code.

Edit:

Everything else is risky or bad style. You have to be absolutely sure that there wasn't any error when committing. When leaving the using block, you don't know if you leave it because an exception is thrown or because you just reached the end of it. When calling Complete, you know.

The transaction block syntax is already the simplest you can do. Just implement the transaction without any special error handling and commit it at the end. You don't have to care and rolling back when any error occurs. Consider, exceptions can be thrown in almost every single line of code (eg. NullReference, Overflows, InvalidOperation etc). So what could be easier than this?

摇划花蜜的午后 2024-08-23 17:27:08

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

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

It means that you don't need to put a manual try/finally (or catch) block (possibly with a "success" flag) in for the failure case. Try rewriting the above code to roll back on error, and look at how much messier it is...

Basically the normal desired behaviour is to only commit if it reaches the end of the block with no exceptions. The simplest way of achieving that is to put a method call to signify success at the end of the block.

梦里南柯 2024-08-23 17:27:08

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

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

If the other implementation had been chosen, then people would be asking the converse question!

Seriously though, the default behaviour in a mechanism designed to protect against partial or incorrect updates surely has to be not to commit, doesn't it?

蝶舞 2024-08-23 17:27:08

我认为,正如 @Jon Skeet 所说,要成功编写的代码量比当前的方式要少(而且不那么难看)。然而,从事务的角度来看,我认为您会希望持悲观态度,并假设除非明确表明成功,否则您会将其回滚。在我看来,错误地提交事务是一个比由于代码错误而意外未能成功提交事务更糟糕的问题。

I think the amount of code to write for success is, as @Jon Skeet says, less (and less ugly) the current way. From a transaction point of view, however, I would think that you would want to be pessimistic and assume that unless success was explicitly indicated you would roll it back. Committing a transaction in error is a much worse problem, in my opinion, than accidentally failing to commit a successful transaction because of a code error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文