【问题标题】:Opening second connection in nested transaction causes error在嵌套事务中打开第二个连接会导致错误
【发布时间】:2015-12-21 19:11:04
【问题描述】:
using (Transactions.TransactionScope tx = new Transactions.TransactionScope()) {
    using (SqlConnection conn = new SqlConnection(CONNECTIONSTRING)) {
        conn.Open();
        var cmd = new SqlCommand("Update Officer1s Set isLocked='Y' where a='b'", conn); //refer to an nonexsiting name on purpose.
        var transaction = conn.BeginTransaction();
        cmd.Transaction = transaction;
        try {
            var a = cmd.ExecuteNonQuery();
        } catch (Exception ex) {
            transaction.Rollback();//Invalid object name 'Officer1s'.
        }

        using (SqlConnection conn2 = new SqlConnection(CONNECTIONSTRING)) {
            conn2.Open(); //throw exception
        }
    }
}

在我的真实应用中,入口方法是被TransactionScope包围的。入口方法调用了很多方法,而且很深。如果在任何连接中 sql 抛出任何 SqlException(为了演示,我故意引用一个不存在的名称)并回滚内部事务,那么我无法打开第二个连接,因为将抛出异常说“事务已中止”。

为什么外部事务中止?是否支持这种用法?

我使用的是 SQL Server 2014。

【问题讨论】:

  • sql-server 中的嵌套事务是一个神话。 “外部”事务除了增加事务计数的值之外什么都没有。并且回滚将回滚事务并将计数器重置为 0。

标签: c# sql-server database transactions


【解决方案1】:

您获得的具体行为可能取决于各种因素,例如您是否使用事务池。然而,一般来说,这并不是交易的工作方式。

连接很昂贵,因此您可能希望保持一个连接打开并反复使用它。一个事务存在于一个连接中,因此在另一个连接上使用同一个事务对象是无效的。

从示例来看,代码看起来不像使用嵌套事务,而是使用“嵌套连接”,这不是正确的方法。应该发生的是:

  • 连接
    • 开始交易
      • DML 声明
      • DML 语句 ...
    • 提交/回滚
    • 开始交易
      • DML 语句 ...
    • 提交/回滚
  • 释放连接

如果需要,您可以在 SQL Server Mgmt Studio 中打开两个查询会话。首先,执行 BEGIN TRAN,然后在表中插入一行。现在,不执行 COMMIT,切换到另一个会话并查询表。您不会看到刚刚添加的行(除非您的 ISOLATION LEVEL 是脏读;我希望不会)。这是交易的隔离属性。

在上面的代码中应该发生的是,当异常被捕获并且事务回滚时,事务对象就完成了。下一个逻辑工作单元从新的 BeginTransaction() 开始。

【讨论】:

    猜你喜欢
    • 2018-06-26
    • 1970-01-01
    • 2014-06-15
    • 2023-03-15
    • 1970-01-01
    • 2015-09-14
    • 2015-01-07
    • 2014-11-09
    • 2011-11-08
    相关资源
    最近更新 更多