我有一个存储过程,在Insert / Update / Delete上的触发器内调用。
问题是此SP中存在某个代码块并不重要。 因此,我想忽略此代码块产生的任何错误。
我在TRY CATCH块中插入了这个代码块。但令我惊讶的是我收到了以下错误:
当前事务无法提交,也无法支持写入日志文件的操作。回滚交易。
然后我尝试使用SAVE& ROLLBACK TRANSACTION和TRY CATCH一起失败,出现以下错误:
无法提交当前事务,也无法回滚到保存点。回滚整个交易。
我的服务器版本是:Microsoft SQL Server 2008(SP2) - 10.0.4279.0(X64)
示例DDL:
IF OBJECT_ID('TestTrigger') IS NOT NULL
DROP TRIGGER TestTrigger
GO
IF OBJECT_ID('TestProcedure') IS NOT NULL
DROP PROCEDURE TestProcedure
GO
IF OBJECT_ID('TestTable') IS NOT NULL
DROP TABLE TestTable
GO
CREATE TABLE TestTable (Data VARCHAR(20))
GO
CREATE PROC TestProcedure
AS
BEGIN
SAVE TRANSACTION Fallback
BEGIN TRY
DECLARE @a INT = 1/0
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION Fallback
END CATCH
END
GO
CREATE TRIGGER TestTrigger
ON TestTable
FOR INSERT, UPDATE, DELETE
AS
BEGIN
EXEC TestProcedure
END
GO
复制错误的代码:
BEGIN TRANSACTION
INSERT INTO TestTable VALUES('data')
IF @@ERROR > 0
ROLLBACK TRANSACTION
ELSE
COMMIT TRANSACTION
GO
答案 0 :(得分:11)
我经历了同样的折磨,我刚解决了! 只需在TRIGGER的第一步添加这一行,您就可以了:
SET XACT_ABORT OFF;
就我而言,我正在处理错误,该错误通过导致错误的批处理和SQL中的错误变量来提供特定表。
XACT_ABORT 的默认值为 ON ,因此即使您正在处理TRY CATCH块内的错误,也不会提交整个事务(就像我一样)我在做什么。设置 OFF 的值将导致即使发生错误也要提交事务。
但是,当没有处理错误时我没有测试它......
欲了解更多信息:
答案 1 :(得分:1)
我建议重新设计这个以便你不会中毒原始事务 - 可能让事务发送服务代理消息(或者只是将相关数据插入到某种形式的队列表中),这样就可以了 - 关键的“部分可以在完全独立的交易中进行。
E.g。你的触发器变成:
CREATE TRIGGER TestTrigger
ON TestTable
FOR INSERT, UPDATE, DELETE
AS
BEGIN
INSERT INTO QueueTable (Col1,Col2)
SELECT COALESCE(i.Col1,d.Col1),COALESCE(i.Col2,d.Col2) from inserted i,deleted d
END
GO
你不应该在可能失败的触发器内做任何事情,除非你做想要强制启动触发操作的事务也失败。
答案 2 :(得分:0)
答案 3 :(得分:0)
我认为你不能在触发器中使用保存点。我的意思是,你可以,但我搜索了它,我看到一些人说他们不工作。如果您为开始事务替换“保存事务”,则会进行编译。当然没有必要,因为你有外部事务控制,内部回滚会回滚所有内容。