MSSQL防止触发器失败时回滚
我有一个插入/更新/删除后触发器,每次对特定表进行插入/更新/删除时,它都会在 AuditTable 中插入一条新记录。如果 AuditTable 中的插入失败,我希望无论如何都插入第一条记录,并将错误记录在另一个表“AuditErrors”中。
这就是我到目前为止所做的,我尝试了很多不同的事情,但如果触发器插入 AuditTable 失败,我就无法让它工作(我通过错误拼写 AuditTable 插入中的列名称来测试这一点)。注意:@sql 是插入到 AuditTable 中。
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF @TranCounter > 0
SAVE TRANSACTION AuditInsert;
ELSE
BEGIN TRANSACTION;
BEGIN TRY
EXEC (@sql)
IF @TranCounter = 0
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- roll back
IF @TranCounter = 0
ROLLBACK TRANSACTION;
ELSE
IF XACT_STATE() <> -1
ROLLBACK TRANSACTION AuditInsert;
-- insert error into database
IF @TranCounter > 0
SAVE TRANSACTION AuditInsert;
ELSE
BEGIN TRANSACTION;
BEGIN TRY
INSERT INTO [dbo].[AuditErrors] ([AuditErrorCode], [AuditErrorMsg]) VALUES (ERROR_NUMBER(), ERROR_MESSAGE())
IF @TranCounter = 0
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- roll back
IF @TranCounter = 0
ROLLBACK TRANSACTION;
ELSE
IF XACT_STATE() <> -1
ROLLBACK TRANSACTION AuditInsert;
END CATCH
END CATCH
I have an after insert/update/delete trigger, which inserts a new record in an AuditTable every time an insert/update/delete is made to a specific table. If the insertion in the AuditTable fails I'd like the first record to be inserted anyway and the error logged in a further table "AuditErrors".
This is what I have so far and I tried many different things but I can't get this to work if the trigger insert into the AuditTable fails (I test this by misspelling the name of a column in the AuditTable insert). NB: @sql is the insert into the AuditTable.
DECLARE @TranCounter INT
SET @TranCounter = @@TRANCOUNT
IF @TranCounter > 0
SAVE TRANSACTION AuditInsert;
ELSE
BEGIN TRANSACTION;
BEGIN TRY
EXEC (@sql)
IF @TranCounter = 0
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- roll back
IF @TranCounter = 0
ROLLBACK TRANSACTION;
ELSE
IF XACT_STATE() <> -1
ROLLBACK TRANSACTION AuditInsert;
-- insert error into database
IF @TranCounter > 0
SAVE TRANSACTION AuditInsert;
ELSE
BEGIN TRANSACTION;
BEGIN TRY
INSERT INTO [dbo].[AuditErrors] ([AuditErrorCode], [AuditErrorMsg]) VALUES (ERROR_NUMBER(), ERROR_MESSAGE())
IF @TranCounter = 0
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
-- roll back
IF @TranCounter = 0
ROLLBACK TRANSACTION;
ELSE
IF XACT_STATE() <> -1
ROLLBACK TRANSACTION AuditInsert;
END CATCH
END CATCH
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是我所知道的将原始交易与触发操作分开的唯一方法。在此示例中,即使审核插入失败,原始插入也会完成。在 2008R2 上测试。
虽然不太漂亮,但它不会回滚事务!
它与受信任的身份验证一起工作得很好:
删除审计表,它仍然完成原始事务。
干杯!
This is the only way I know of separating the original transaction from the trigger action. In this example the original insert completes even though the audit insert fails. Tested on 2008R2.
It's not pretty but it won't rollback the transaction!
It worked just fine with trusted authentication:
Drop the Audit table and it still completes the original transaction.
Cheers!
您可以考虑使用 BEGIN TRAN/ROLLBACK 来代替使用 sqlcmd。
请注意,即使回滚命令将撤消自导致触发器触发的语句开始以来所做的所有更改,后续命令所做的任何更改都不会。
如果审计表中插入数据的事务回滚,您所要做的就是重复执行@sql中的代码:
Instead of using sqlcmd, you may consider playing with BEGIN TRAN/ROLLBACK a little bit.
Note that, even tho a rollback command will undo every change made since the start of the statement which caused the trigger to fire, any changes made by subsequent commands will not.
All you have to do is to repeat the execution of the code in @sql if the transaction in which data is inserted in the audit table gets rolled back: