首页 > 解决方案 > 在嵌套事务范围内打开两个 SQL 连接时挂起事务

问题描述

我试图了解下面的代码有什么问题:

using (var scope1 = new TransactionScope())
{
    var connection1 = new SqlConnection("...");
    connection1.Open();

    using (var scope2 = new TransactionScope())
    {

        SqlConnection connection2 = new SqlConnection("...");
        connection2.Open();

        connection2.Close();
        scope2.Complete();

    }

    connection1.Close();
    scope1.Complete();
}

应用程序非常复杂,因此存在TransactionScope. 在上面的代码中,当一个连接打开时,在 SQL Server 中创建了事务,所以实际上创建了两个事务,因为连接被打开了两次。

我通过调用以下 SQL 语句检查了这一点:

SELECT * FROM sys.sysprocesses WHERE open_tran = 1

当 scope1 中的环境事务完成时,数据库中还有一个事务。connection2.Close() 创建的事务仍然挂起。我的问题是为什么这个交易仍然存在以及如何更正代码。

编辑:

我想使用在外部定义的一个 SQL 连接TransactionScope可能是一个答案,但也许存在更好的东西?

标签: c#sql-server

解决方案


该代码将需要分布式事务,因为您同时打开了两个单独的 SqlConnection 对象。如果在启动第二个 TransactionScope 之前关闭 SqlConnection,则初始连接和事务将被重用,您将不需要 DTC 事务。

无论如何,我认为这是进行 DTC 交易的无害副作用,其跟踪方式略有不同。查看

  select st.session_id, is_local, is_enlisted, at.transaction_state
  from sys.dm_tran_session_transactions st
  join sys.dm_tran_active_transactions at
    on at.transaction_id = st.transaction_id 

对我来说,为打开的第二个会话(spid 65)输出一行,并指示事务已提交。

session_id  is_local is_enlisted transaction_state
----------- -------- ----------- -----------------
65          0        1           6

transaction_state=6 表示事务已提交。https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-active-transactions-transact-sql?view=sql-server-2017


推荐阅读