BEGIN TRY / CATCH和MSDTC错误

时间:2014-01-08 11:31:03

标签: 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

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

知道为什么会这样吗?

稍后编辑:

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

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

  3. 欢迎任何评论/评论。

3 个答案:

答案 0 :(得分: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.

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

Msg 8525, Level 16, State 1, Line 1 
Distributed transaction completed. Either enlist this session in a new 
transaction or the NULL transaction.

如果满足以下条件,则会出现此问题:

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.

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

原因

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

替代方法

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

更新

您需要在服务器参数中将“remote proc trans”配置为“1”。

例如:

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

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

更新更新

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

答案 1 :(得分:4)

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

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

最好继续@@TRANCOUNT而不是XACT_STATE()(至少在这种情况下)。

使它工作,改变这样(虽然我不支持单表的TRAN):

IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION

答案 2 :(得分:0)

BEGIN TRANSACTION在运行语句的服务器和链接服务器之间启动分布式事务,因为您可以对两个服务器运行更新。当INSERT失败时,它需要取消分布式事务,因此会出现错误。所以你必须处理两个级别的错误(插入和事务)。在这种情况下,您需要两个TRY/CATCH块,如下所示:

SET XACT_ABORT ON;

BEGIN TRY  
    BEGIN TRANSACTION   

    BEGIN TRY
        -- Error is on this line
        INSERT INTO linkedsrv1.db1.[dbo].tbl1 ([IdWebsite], [IdProductType]) 
        VALUES (1200, 0)
    END TRY
    BEGIN CATCH
        SELECT 'Insert Error', ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(), ERROR_STATE()
        RAISERROR (15600,-1,-1, 'INSERT ERROR');
    END CATCH 

    COMMIT TRANSACTION
END TRY  
BEGIN CATCH
    SELECT 'Transaction Error', ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_SEVERITY(), ERROR_STATE()

    IF XACT_STATE() != 0   
        ROLLBACK TRANSACTION
END CATCH