BEGIN TRY/CATCH和MSDTC错误

use*_*183 13 sql-server msdtc

1 /以下代码片段显示了预期的错误:INSERT语句与FOREIGN KEY约束FK _...冲突.

SET XACT_ABORT ON;

BEGIN TRANSACTION

    INSERT INTO linkedsrv1.db1.[dbo].tbl1 ([Col1], [Col2])  
    VALUES (1200, 0)                

COMMIT TRANSACTION
Run Code Online (Sandbox Code Playgroud)

2 /但是当我把它放在BEGIN TRY/CATCH中时,错误消息是模糊的:消息1206,级别18,状态118,行18 Microsoft分布式事务处理协调器(MS DTC)已取消分布式事务.

SET XACT_ABORT ON;

BEGIN TRY  
    BEGIN TRANSACTION   

        -- Error is on this line
        INSERT INTO linkedsrv1.db1.[dbo].tbl1 ([IdWebsite], [IdProductType])  
        VALUES (1200, 0)   

    COMMIT TRANSACTION
END TRY  
BEGIN CATCH
    PRINT 'Error' -- Code not reached

    SELECT ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(), ERROR_STATE()

    IF XACT_STATE() != 0   
        ROLLBACK TRANSACTION
END CATCH
Run Code Online (Sandbox Code Playgroud)

知道为什么会这样吗?

稍后编辑:

  1. 它适用于我删除不需要的显式事务.当我放入BEGIN/COMMIT TRAN时,我仍然不清楚为什么会出现这个错误.

  2. 如果我在链接服务器上的多个表中有多个插入,我会得到相同的错误.

欢迎任何评论/评论.

小智 6

来自MSDN:

症状

请考虑以下情形.您使用SQL Server 2005中的SQL Native Client OLE DB提供程序(SQLNCLI)来创建链接服务器.您创建分布式事务.分布式事务包含使用链接服务器从表中检索数据的查询.提交分布式事务时,您可能会收到以下错误消息:

Msg 1206, Level 18, State 167, Line 3 
The Microsoft Distributed Transaction Coordinator (MS DTC) has cancelled 
the distributed transaction.
Run Code Online (Sandbox Code Playgroud)

此外,在发生此行为后运行查询时,您可能会收到以下错误消息:

Msg 8525, Level 16, State 1, Line 1 
Distributed transaction completed. Either enlist this session in a new 
transaction or the NULL transaction.
Run Code Online (Sandbox Code Playgroud)

如果满足以下条件,则会发生此问题:

You use the SQLNCLI provider to create a linked server between two 
instances of SQL Server 2005.

The XACT_ABORT option is set to ON.

In the distributed transaction, you try to release a rowset before 
all rows in the rowset are processed.
Run Code Online (Sandbox Code Playgroud)

注意如果在分布式事务中调用ReleaseRows方法以在应用程序中提交分布式事务之前释放行集,也可能会出现此问题.

原因

出现此问题的原因是SQLNCLI提供程序错误地向链接服务器发送注意信号以回滚分布式事务.

替代方法

若要防止SQLNCLI提供程序向服务器发送注意信号,请使用SQLNCLI提供程序完全使用OLE DB使用者创建的任何行集.

更新

您需要在服务器参数中将"remote proc trans"配置为"1".

例如:

exec sp_configure'remote proc trans','1'使用override重新配置

这将使您执行任何分布式查询.

更多更新

如果您也在前端使用.Net框架,那么我认为您可以使用 TransactionScope类.从查询中删除事务并将事务置于代码级别.

  • +1,感谢您的信息,似乎满足所有条件,除了"您尝试在处理行集中的所有行之前释放行集".我没有得到的含义.另外,我在解决方法中没有得到这个想法,我应该做些什么呢? (2认同)

小智 4

我已经经历过这种痛苦了!如果您在单个表上执行任何 CRUD 操作,则不需要 TRANSACTION。

在这种情况下,问题是XACT_STATE()返回 -1,因为活动事务中存在错误。但是,ROLLBACK TRANSACTION失败了,因为没有发生任何交易。您只执行了一项事务,INSERT该事务失败了,因此没有其他事务可以回滚。

@@TRANCOUNT继续传递总是比XACT_STATE()(至少在这种情况下)更好。

要使其工作,请像这样进行更改(尽管我不支持单表的 TRAN):

IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION