放入事务时执行存储过程失败

时间:2020-09-07 13:28:43

标签: sql-server tsql

我有一个要通过链接服务器执行的查询。查询看起来像这样:

USE db1;

SET xact_abort ON;

DECLARE @statement NVARCHAR(max);
SET @statement = 'EXECUTE (''INSERT INTO T1(V1, V2) VALUES (1, 2)'') AT LS1';

BEGIN try
    BEGIN TRANSACTION

    EXEC Sp_executesql @statement

    COMMIT TRANSACTION
END try

BEGIN catch
    IF ( Xact_state() ) = -1
      BEGIN
          PRINT Error_message()

          ROLLBACK TRANSACTION
      END

    IF ( Xact_state() ) = 1
      BEGIN
          PRINT 'COMMIT OPEN TRANSACTION'

          COMMIT TRANSACTION
      END

    INSERT INTO tblerrmsg (errornumber, errorseverity, errorstate, errorline, errormessage) EXECUTE Usp_geterrorinfo;
END catch

此操作失败,并在我的TblErrMsg表中添加了一个条目。

错误编号= 8501,错误严重性= 16,错误状态= 3,错误行= 1,错误消息=服务器“ XXX”上的MSDTC不可用。

因此,我研究了特定的错误消息,并检查了服务器上是否正在运行“分布式事务处理协调器服务”,但是情况已经如此。即使重新启动服务也没有带来任何变化。接下来,我尝试删除该事务并执行以下过程:

USE db1;

DECLARE @statement NVARCHAR(max);
SET @statement = 'EXECUTE (''INSERT INTO T1(V1, V2) VALUES (1, 2)'') AT LS1';

BEGIN try
    EXEC Sp_executesql @statement
END try

BEGIN catch
    PRINT Error_message()
END catch

这一次它起作用了。没有错误,并且INSERT也起作用。所以我想知道真正的问题是什么。显然,执行该过程或链接服务器连接似乎没有问题。

有人遇到过类似的问题,或者对此行为有解释吗?

1 个答案:

答案 0 :(得分:0)

在指定显式事务时,您可能缺少关键字DISTRIBUTED。

代替

BEGIN TRANSACTION

尝试

BEGIN DISTRIBUTED TRANSACTION

根据Docs,这是指定“ ...由Microsoft分布式事务处理协调器(MS DTC)管理的Transact-SQL分布式事务的开始”的方式。

没有显式事务,默认行为afaik是跨链接服务器的事务不能保证是原子的,也不能回滚。这就是为什么在未指定显式事务的情况下它起作用的原因。

当指定的BEGIN TRANSACTION不带'DISTRIBUTED'语句时,该语句将询问该过程包含链接服务器引用时不可能发生的事情。