用于IDbConnection / IDbTransaction安全使用?

时间:2013-06-03 18:22:22

标签: c# vb.net transactions database-connection using-statement

虽然我的假设似乎听起来很主观,但经过一些研究后,我发现找到喜欢假人Try/Catch而不是使用Using statement进行IDbConnection/IDbTransaction处理的开发人员并不罕见(关闭/提交/回滚)。

即使是一些经验最丰富的开发人员和一些新开发人员也是如此。我故意不会在StackOverflow或论坛链接上引用任何问题作为示例,因此人们不会被冒犯。从what I found开始,Using语句为safe to use(无双关语)。

它有什么问题吗?请考虑以下代码:

Public Sub Commit()
  Dim cn As IDbConnection = {CREATE_CONNECTION}
  Dim tran As IDbTransaction = Nothing

  cn.Open()
  Try
    tran = cn.BeginTransaction
    'run some queries here
    tran.Commit()
  Catch ex As Exception
    If Not tran Is Nothing Then tran.Rollback()
    Throw
  Finally
    cn.Close()
  End Try
End Function

假设{CREATE_CONNECTION}是创建连接的Sub的占位符,具体取决于数据库供应商,根据所有可能的最佳实践编写,并且不需要进一步改进。

有没有理由不能重写上述代码:

Using cn As IDbConnection = {CREATE_CONNECTION}
  cn.Open()
  Using tran As IDbTransaction = cn.BeginTransaction
    'run some queries here
    tran.Commit()
  End Using
End Using

显然,版本#2对它正在做的事情更直观。但也许我错过了一些重要的东西?像供应商特定的数据访问库实现那些内部不会在Transaction.Commit上调用Connection.Close和/或Dispose的东西?这种方法在不久的将来会退役,还是在现代编程模式/最佳实践中不被视为足够清晰?单声道/移动应用开发工具缺少Using关键字的调试支持?

我正在寻找支持或否认这一观点的任何答案。最好是带有原始文档引用的那个,如Do not use Using with IDbTransaction when ...。博客或个人经历的链接也可以。

2 个答案:

答案 0 :(得分:17)

我完全和你在一起;应该是using,并且不需要明确的Close()。交易有点棘手;所显示的代码目前肯定是矫枉过正的,但并未完全定义Dispose()应该进行回滚。实际上,在我看过的每个实现中都会发生的事情,但即使DbTransaction(大多数提供商使用的)实际上并没有这样做,但有点令人烦恼。与TransactionScope形成对比,明确定义没有提交的Dispose()计为回滚。因此,我倾向使用(原谅C#):

using(var conn = GetOpenConnection())
using(var tran = conn.BeginTransaction()) {
    try {
        // TODO: do work
        tran.Commit();
    } catch {
        tran.Rollback();
        throw;
    }
}

在复杂性方面介于两者之间。它至少没有弄乱null - 支票。

答案 1 :(得分:13)

您所看到的是开发人员根据文档编写的代码(“Good Thing”)。基类DbTransaction(用于大多数数据提供者的事务实现)明确指出its documentation

  

Dispose应该回滚事务。但是,Dispose的行为是特定于提供者的,不应该替换调用Rollback。