在嵌套事务中打开第二个连接会导致错误

时间:2015-12-21 19:11:05

标签: c# sql-server database transactions

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包围。 entry方法调用了很多方法并且非常深入。如果在任何连接中sql抛出任何SqlException(为了演示,我故意引用一个非兴奋的名称)并回滚内部事务,然后我无法打开第二个连接,因为将抛出异常说"事务已经。中止"

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

我正在使用SQL Server 2014。

1 个答案:

答案 0 :(得分:0)

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

连接很昂贵,所以你想要打开一个连接并一遍又一遍地使用它。连接中存在事务,因此在另一个连接上使用相同的事务对象无效。

根据样本判断,代码看起来并不像是使用嵌套事务,而是使用嵌套连接",这不是正确的方法。应该发生的是:

  • 连接
    • 开始交易
      • DML声明
      • DML声明......
    • 提交/回滚
    • 开始交易
      • DML声明......
    • 提交/回滚
  • 发布连接

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

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