Sql Server 2014 sp_reset_connection 事务内的行为

Sql Server 2014 sp_reset_connection behavior inside transaction

sp_reset_connection 在事务中 运行 时的行为是什么?我正在寻求澄清,以便我可以决定是否需要重组我的代码,或者我是否可以保持原样。

我有一个使用 ORM(Petapoco) 的 c# 应用程序,它似乎不尊重环境事务 (System.Transactions.TransactionScope)。我可以在 Sql Profiler 中看到交易开始,但在交易中的每次调用之前,ORM 都会发送一个 sp_reset_connection 调用。当我的环境事务完成时,我还在 Sql Profiler 中看到事务提交事件。

我在 Whosebug 上看到其他问题,这些问题表明在调用 sp_reset_connection 时交易隔离范围被重置(参见:What does “exec sp_reset_connection” mean in Sql Server Profiler?),但我无法找到有关在事务内部调用 sp_reset_connection 时具体发生的情况的任何信息。

sp_reset_connection 存储过程没有很好的文档记录,因为它是一个内部存储过程,从不直接调用。请注意,它可能会在将来更改或删除,恕不另行通知。话虽这么说,但了解一些有关故障排除和关联 activity 跟踪数据的内部机制很有用。

proc 的目的是将连接环境状态恢复到新打开的连接状态以支持连接池。客户端 API 指定是否通过设置 RESETCONNECTIONRESETCONNECTIONSKIPTRAN 位来重置连接水池。 SQL 服务器内部调用 sp_reset_connection 您在设置这些标志时在跟踪中看到的 RPC。

TDS 协议文档描述了这些标志,因此我们可以推断这就是 sp_reset_connection 在幕后所做的事情。以下是文档的摘录:

RESETCONNECTION (Introduced in TDS 7.1) (From client to server) Reset this connection before processing event. Only set for event types Batch, RPC, or Transaction Manager request. If clients want to set this bit, it MUST be part of the first packet of the message. This signals the server to clean up the environment state of the connection back to the default environment setting, effectively simulating a logout and a subsequent login, and provides server support for connection pooling. This bit SHOULD be ignored if it is set in a packet that is not the first packet of the message.

This status bit MUST NOT be set in conjunction with the RESETCONNECTIONSKIPTRAN bit. Distributed transactions and isolation levels will not be reset. 0x10

RESETCONNECTIONSKIPTRAN (Introduced in TDS 7.3) (From client to server) Reset the connection before processing event but do not modify the transaction state (the state will remain the same before and after the reset). The transaction in the session can be a local transaction that is started from the session or it can be a distributed transaction in which the session is enlisted. This status bit MUST NOT be set in conjunction with the RESETCONNECTION bit. Otherwise identical to RESETCONNECTION.

低级客户端 API(此处为 SqlClient)通过根据需要设置这些标志来间接控制 sp_reset_connection 的行为。当在 TransactionScope 之外重用连接时,设置 RESETCONNECTION 标志,如此网络数据包跟踪 (Wireshark) 中所示:

下面是在 TransactionScope using 块的范围内对重用连接发出的第一个请求的跟踪:

如您所见,TransactionScope内的重置不会回滚事务。因此,即使您的 ORM 遵循 open/execute/close 数据访问模式,您的外部 TransactionScope 事务上下文也将受到尊重。只要您在退出事务范围之前调用 TransactionScope.Complete,事务就会被提交。您可以将 TM Commit Tran 完成事件包含到您的 Profiler 跟踪中,以在 TransactionScope 退出时查看提交。

顺便说一句,Profiler/SQL 跟踪已弃用。继续使用扩展事件。此外,正如另一个答案中所建议的,当您使用 TransactionScope 时,请务必指定所需的事务隔离级别(例如,读取已提交)。默认是可序列化的,这可能会产生不必要的阻塞和死锁等副作用。我建议您仅在特别需要严格的隔离级别时才使用可序列化。