10

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

即使对于一些经验最丰富的开发人员和一些新开发人员来说也是如此。我故意不以 StackOverflow 或论坛链接上的任何问题为例,这样人们就不会生气。根据我的发现Using语句可以安全使用(不是双关语)。

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

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 .... 博客链接或个人经验也可以。

4

2 回答 2

19

我完全支持你的连接;那应该是using,并且不需要显式的Close()。交易有点棘手;目前显示的代码肯定是矫枉过正,但没有完全定义Dispose()应该回滚。实际上,这就是我看过的每一个实现中都会发生的事情,但有点令人烦恼的是,即使DbTransaction(大多数提供者使用)实际上并没有这样做。TransactionScope与明确定义Dispose()没有提交的 a 算作回滚的地方形成对比。因此,我倾向于使用(请原谅 C#):

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

就复杂性而言,这介于两者之间。null至少,它不会乱用-checks。

于 2013-06-03T18:35:23.750 回答
13

您所看到的是开发人员根据文档进行编码(“好事”)。基类 DbTransaction(用于大多数数据提供者的事务实现)在其文档中明确说明:

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

于 2013-06-03T18:36:10.330 回答