TransactionScope事务升级与SqlConnection连接池的技术疑问
关于.NET TransactionScope在Linux下触发分布式事务的疑问解答
问题1:是否能同时存在两个底层ClientConnectionId相同的SqlConnection对象?
可以,但这两个SqlConnection实例本质上共享同一个物理数据库连接,且不能同时处于打开状态。
连接池是按连接字符串匹配复用物理连接的:
- 当第一个
SqlConnection打开并使用后关闭,归还到连接池;此时创建第二个SqlConnection并打开,只要连接字符串一致,就会复用之前的物理连接,二者的ClientConnectionId会完全相同。 - 但如果第一个
SqlConnection还处于打开状态,再打开第二个SqlConnection,.NET无法复用已被占用的物理连接,只能获取新的物理连接,此时两个实例的ClientConnectionId就会不同。
问题2:为何同一连接字符串、同一服务器的两个独立连接会触发事务升级?
因为你在同一TransactionScope内同时打开了两个独立的物理数据库连接,这触发了分布式事务的升级条件。
SQL Server的本地轻量级事务要求:事务内所有数据库操作必须绑定到同一个物理连接。而TransactionScope的事务管理器一旦检测到事务跨越了多个物理连接——哪怕是同一服务器、同一连接字符串——就会自动尝试升级为分布式事务。Linux环境下没有MSDTC(分布式事务协调器)支持,所以会抛出异常。
而EF Core的两个DbContext能正常工作,是因为EF Core默认的连接管理策略:
- 它会延迟打开连接(直到真正需要执行数据库操作时才打开),并且操作完成后立即关闭连接,归还到连接池。
- 第二个DbContext执行操作时,能从连接池复用第一个DbContext归还的物理连接,整个事务全程只使用一个物理连接,符合本地事务的要求,自然不会触发分布式事务升级。
内容的提问来源于stack exchange,提问作者mdzieg
相关产品推荐
相关产品推荐

