我想知道更多关于在链接服务器上执行跨服务器查询时自动提交事务在幕后发生的事情。
我天真地认为,在执行自动提交事务时,编译器/SQL Server/其他东西只是在所有语句前添加 aBEGIN TRANSACTION
并在所有语句后附加 aCOMMIT TRANSACTION
因为一切都在技术上包含在事务中(总是创建事务是一种不好的做法吗?)。我确信这是不正确的,也是我困惑的根源,为什么在没有明确说明的情况下执行跨服务器UPDATE
工作BEGIN TRANSACTION
但明确说明一个没有。根据 Microsoft ( https://learn.microsoft.com/en-us/sql/t-sql/language-elements/begin-transaction-transact-sql?view=sql-server-2017 ) 的说法,一个显式BEGIN TRANSACTION
的UPDATE
引用链接服务器上的表的查询升级为分布式事务;由于链接服务器上未配置分布式事务,因此我收到一条错误消息。自动提交设置如何避免这种情况?它如何不升级为分布式事务?自动提交设置是否将数据发送到链接服务器,但不通过 Microsoft 分布式事务处理协调器 (MS DTC)“侦听”来自链接服务器的响应;因此,如果发生错误,它会“默默地”失败吗?
自动提交不会升级为分布式事务:
UPDATE l
SET l.RecordKey = s.RecordKey
FROM LinkedServer.ExampleDatabase.dbo.ExampleTable AS l
INNER JOIN ServerWithActiveConnection.ExampleDatabase.dbo.ExampleTable AS s
ON l.Value1 = s.Value1;
显式事务确实升级为分布式事务(在我的例子中是错误):
BEGIN TRANSACTION
UPDATE l
SET l.RecordKey = s.RecordKey
FROM LinkedServer.ExampleDatabase.dbo.ExampleTable AS l
INNER JOIN ServerWithActiveConnection.ExampleDatabase.dbo.ExampleTable AS s
ON l.Value1 = s.Value1;
COMMIT TRANSACTION;
我应该补充一点,这些语句是在 SQL Server Management Studio 中运行的。
鉴于链接服务器是一个外部/单独的连接,我希望它可以单独处理/管理,就像通过
SqlClient
在 SQLCLR 中。作为一个单独的连接,是否尝试加入当前事务是可选的(这是通过Enlist= {true | false}
连接字符串关键字处理的)。我猜测is_remote_proc_transaction_promotion_enabled
/“为 RPC 启用分布式事务的提升”的链接服务器属性等同于Enlist
连接字符串关键字。话虽如此,还是有一些东西被忽略了(包括在我原来的回答中被忽略了):该选项的名称是“为 RPC启用分布式事务的促进”(强调我的)。突出显示的部分在这里非常重要。此选项影响链接服务器上的存储过程调用,而不影响常规的即席查询批处理。因此,该选项不应与您在问题中描述的行为相关。
我的(有根据的)猜测是,对于临时查询,当前事务中“登记”的选项对于自动提交事务默认为“false”。但是,对于显式事务,您是在告诉 SQL Server 中的所有语句
BEGIN TRAN ... COMMIT TRAN
都应被视为原子操作,因此远程连接然后会尝试在当前事务中登记。仅供参考:此行为应该与执行 SSMS 中的语句无关。那只是一个将语句提交给 SQL Server 执行的客户端。即使通过SQLCMD.EXE或
SqlCient
在 .NET 应用程序等中执行,它也应该是相同的行为。更新
关于对此进行测试,我建议 OP 使用 SQL Server Profiler 或扩展事件来捕获事务登记/提升到分布式事务。OP 回复: