You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8分布式事务调用Dispose时发生死锁,寻求解决方法

问题分析与解决方案

问题根源

你遇到的TransactionScope.Dispose()死锁,核心原因在于显式调用SqlConnection.Close()提前释放了连接:

  • 手动关闭连接时,连接会被放回连接池,但此时分布式事务的提交逻辑还未完成(ts.Complete()仅标记事务需要提交,实际提交操作在Dispose()阶段执行)。
  • 事务管理器在Dispose()时需要和数据库交互完成分布式事务的提交,但提前释放的连接可能导致事务资源无法正确关联,或连接池中的连接被其他操作占用,进而引发死锁。
  • 注释ts.Complete()后,事务会直接回滚,Dispose()阶段无需执行复杂的提交逻辑,因此不会触发死锁。

修复方案

1. 移除显式Close调用,改用using块自动管理资源

SqlConnection和TransactionScope都实现了IDisposable,直接用using块包裹即可自动处理资源释放,无需手动调用Close()或Dispose()。修正后的代码如下:

TransactionManager.ImplicitDistributedTransactions = true;
var transactionOptions = new TransactionOptions();
transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
transactionOptions.Timeout = TimeSpan.FromSeconds(3600);

// 用using块包裹TransactionScope,自动处理Dispose
using (IDbConnection connection1 = new SqlConnection(infocitiConnectionString))
using (IDbConnection connection2 = new SqlConnection(storageConnectionString))
using (var ts = new TransactionScope(TransactionScopeOption.Required, transactionOptions))
{
    connection1.Open();
    //connection1.Execute(sql: sqlDelete);

    connection2.Open();
    //connection2.Execute(sql: sqlInsert);

    ts.Complete();
}

这样可以确保连接在事务完成前保持登记状态,让事务管理器正确处理分布式事务的提交流程。

2. 确认连接字符串与分布式事务配置

  • 检查SQL Server连接字符串是否包含Enlist=true(默认值为true,若手动设置为false会导致事务无法登记到分布式事务)。
  • 若涉及远程数据库,确保两台服务器的MSDTC服务已启用并配置正确(分布式事务依赖MSDTC进行跨资源协调)。

3. 排查数据库端锁资源

死锁也可能源于数据库端的资源冲突,可通过以下SQL查询当前锁状态:

-- 查看当前事务锁
SELECT * FROM sys.dm_tran_locks
-- 查看阻塞进程
EXEC sp_who2

确认是否有其他未提交的事务占用了目标资源,导致提交时等待锁释放。

4. 优化事务内操作时长

尽量缩短事务执行时间,避免在事务内执行非必要的耗时操作,减少锁占用时间,降低死锁概率。


内容的提问来源于stack exchange,提问作者Maksim Perevoshchikov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 06:10:13