2010-02-17 137 views
23

很多例子了数据库事务的主张有明确的回退,沿着线:显式事务回滚是否必需?

using (var transaction = ...) 
{ 
    try 
    { 
     // do some reading and/or writing here 

     transaction.Commit(); 
    } 
    catch (SqlException ex) 
    { 
     // explicit rollback 
     transaction.Rollback(); 
    } 
} 

不过,我倾向于这样做:

using (var transaction = ...) 
{ 
    // do some reading and/or writing here 

    transaction.Commit(); 
} 

当异常发生时,我只是凭着隐式回滚未提交的事务。

依赖这种隐式行为是否存在问题?有没有人有一个令人信服的理由,为什么我不应该这样做?

+1

您的问题中的示例代码可以说是有缺陷的,因为它不会重新抛出。也许忘记这种倾向是避免这种模式的理由? :) – 2010-02-17 15:30:24

+0

谁说你想重新抛出?在很多情况下,回滚事务可以被视为处理异常。 – 2010-02-17 16:08:47

+1

你提出了两个不同的“选项”。对于第一个行为像第二个,它必须重新抛出。为了相当,两个例子中的一个需要改变。 – 2010-02-17 17:54:40

回答

13

不,它不是特别需要,但是我能想到的两个原因为什么它可能是一个好主意:

  • 清晰

有些人可能会认为,使用transaction.Rollback()使得下更清楚什么情况下交易将不会被提交。当事务回滚或提交

  • 释放锁

当与交易处理重要的是要实现一定的锁才会被释放。如果您使用的是using语句,那么事务将在事务处理完成时回退,但如果由于某种原因您需要在using块中执行一些错误处理,则回滚事务(移除锁定)在执行复杂/耗时的错误处理之前。

1

我想可以回答第一种方法对维护你的代码的人更具可读性。编码的明确性使目标清晰而迅速。虽然隐含的回滚对你来说很清楚,并且可能任何人对交易处理的掌握不止一个知识,但对其他人可能不是。这就是说,有几条评论很快就会纠正这一点。唯一的问题是如果隐式回滚不是该对象的文档化特征。

所以,我想说,如果您提供了对操作的评论,并且您可以依赖隐式操作,那么没有充分的理由去采用显式方法。

1

正确编写的ADO.NET连接将回滚未明确提交的事务。所以这不是必须的。

我看到一个明确的Rollback()的主要好处是它能够在那里设置断点,然后检查连接或数据库以查看发生了什么。未来的代码维护者对于不同执行路径下发生的事情也更加清楚。

0

只要交易在using()块中完全独立,那么您就很好。但是,如果某人(如果您从调用方传递了现有的事务对象)问题可能会出现,并且确实会出现问题。但这是一个不同的场景......

3

我看到两个问题您的使用情况:

  1. 你依靠交易的Dispose()方法来回滚未提交的事务,建立一个第三方的实现了IDisposable的依赖。在这种情况下,风险是微不足道的,但不是一个好的做法。
  2. 您错过了记录和/或处理异常的机会。此外,我会赶上异常而不是SqlException。
+0

异常管理和日志记录进一步发生在我的堆栈中。第一个样本不是我的 - 这就是您通常会找到的示例交易管理代码。 – 2010-02-17 14:59:39

+0

IMO,日志应该总是尽可能接近例外。使用事务总是有可能发生异常,所以应该总是有try..catch块。 – 2010-02-17 15:21:07

+2

那么,这是你的意见,你有权:) – 2010-02-17 16:07:24