显式调用事务回滚或让异常触发隐式回滚是一种更好的做法吗?

Ela*_*lan 20 sql transactions rollback

在下面的代码中,如果在执行SQL语句时抛出任何异常,我们应该期望在事务未提交时对事务进行隐式回滚,它会超出范围并被处置掉:

using (DbTransaction tran = conn.BeginTransaction())
{
    //
    // Execute SQL statements here...
    //
    tran.Commit();
}
Run Code Online (Sandbox Code Playgroud)

以上是一种可接受的做法,还是应该捕获异常并显式调用tran.Rollback(),如下所示:

using (DbTransaction tran = conn.BeginTransaction())
{
    try
    {
        //
        // Execute SQL statements here...
        //
        tran.Commit();
    }
    catch
    {
        tran.Rollback();
        throw;
    }
}
Run Code Online (Sandbox Code Playgroud)

Rem*_*anu 21

前任的.如果您在类似主题上查找MSND示例,例如TransactionScope,它们都支持隐式回滚.这有很多原因,但我只会给你一个非常简单的原因:当你捕获异常时,事务可能已经回滚了.许多错误回滚挂起的事务,然后它们将控制权返回给客户端,其中ADO.Net 在事务已经回滚到服务器上之后引发CLR SqlException (1205 DEADLOCK是此类错误的典型示例),因此显式Rollback()呼叫充其量只是一个无操作,更糟糕的是错误.DbTransaction(例如SqlTransaction)的提供者应该知道如何处理这种情况,例如.因为服务器和客户端之间存在明确的聊天,通知事务已经回滚的事实,并且该Dispose()方法做了正确的事情.

第二个原因是事务可以嵌套,但ROLLBACK的语义是一个回滚回滚所有事务,所以你只需要调用一次(不像那样Commit()只提交最内部事务,必须为每个事务调用配对)开始).再一次,Dispose()做对了.

更新

MSDN示例SqlConnection.BeginTransaction()实际上支持第二种形式,并Rollback()catch块中进行显式处理.我怀疑技术作家只是打算在一个单独的样本中显示,Rollback()Commit()注意他需要在周围添加第二个try/catch块Rollback以避开我最初提到的一些问题.