忽略触发器中的错误

时间:2012-04-02 06:09:06

标签: sql-server transactions triggers try-catch

我有一个存储过程,在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

4 个答案:

答案 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)

我认为你不能在触发器中使用保存点。我的意思是,你可以,但我搜索了它,我看到一些人说他们不工作。如果您为开始事务替换“保存事务”,则会进行编译。当然没有必要,因为你有外部事务控制,内部回滚会回滚所有内容。