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
知道为什么会这样吗?
稍后编辑:
如果我删除不需要的显式事务,它的作用。当我放入BEGIN / COMMIT TRAN时,我仍然不清楚为什么会出现这个错误。
如果我在链接服务器上的多个表中有多个插入,我会收到同样的错误。
欢迎任何评论/评论。
答案 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