我正在尝试使用Microsoft Server 2005在触发器中放置try-catch语句。
BEGIN TRANSACTION
BEGIN TRY
--Some More SQL
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF (XACT_STATE()) = -1
BEGIN
ROLLBACK TRANSACTION;
END;
END CATCH
问题是如果try-catch块捕获了某些内容,我不希望触发器失败。目前,我收到错误“交易在触发器中结束。批次已中止。”如果交易失败。如何让触发器优雅地失败?
此外,如果我删除了该事务,我会收到错误“事件在触发器中注定。批处理已中止。”。
BEGIN TRY
--Some More SQL
END TRY
BEGIN CATCH
return
END CATCH
有什么方法吗?
答案 0 :(得分:8)
根据我的经验,触发器中try catch中捕获的任何错误都将回滚整个事务;您可以使用保存交易。我想你需要看看“更多sql”中发生的事情,并确定你是否可以编写case / if语句来阻止错误。
根据您正在做的事情,您可能会使用save transaction并在捕获中捕获
在你的代码中有类似的东西
SAVE TRANSACTION BeforeUpdate;
BEGIN TRY
--Some More SQL
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION BeforeUpdate;
return
END CATCH
答案 1 :(得分:7)
不要在触发器中回滚,也不需要启动事务。
ROLLBACK TRANSACTION
也将回滚原始DML触发器和额外的触发器事务。因此批次将被中止
编辑:
我建议你的catch块没有“RETURN”,只需让代码完成即可 我从来没有忽略过触发器中的陷阱错误(但我确实在使用rollback和raiserror的触发器中使用TRY / CATCH来重新抛出)所以这是猜测,但是返回可能是触发器中的异常退出条件
另外,首先尝试避免错误情况。更改--some more sql
以避免错误。例如,添加if exists(...
以测试重复的第一个或类似的
答案 2 :(得分:3)
使用SET XACT_ABORT OFF。当Transact-SQL语句遇到错误时,它只是引发了错误消息并且事务继续处理。 以下代码用于创建触发器:
Create TRIGGER [dbo].tr_Ins_Table_Master ON [dbo].Table_Master
AFTER INSERT
AS
BEGIN
set xact_abort off
BEGIN TRY
--your SQL
INSERT INTO Table_Detail
SELECT MasterID,Name FROM INSERTED
END TRY
BEGIN CATCH
select ERROR_MESSAGE()
END CATCH
END
答案 3 :(得分:2)
为避免在触发操作之前丢失事务数据,您需要调用COMMIT TRAN。在TRY / CATCH块之前执行此操作,您将获得所需的结果。
示例:
COMMIT TRAN
BEGIN TRY
-- possible error occurs here...
END TRY
BEGIN CATCH
PRINT 'Error on line ' + CAST(ERROR_LINE() AS VARCHAR(10))
PRINT ERROR_MESSAGE()
END CATCH
它仍会抛出以下错误 - 不确定如何避免:
The transaction ended in the trigger. The batch has been aborted.
但是原始事务和触发器事务都应该成功提交。
更新: 要避免异常上一个错误,请在TRY语句中调用BEGIN TRAN。注意,Microsoft建议不要在触发器中调用COMMIT TRAN,但如果不可避免,这应该适合您。
示例:
COMMIT TRAN
BEGIN TRY
BEGIN TRAN
答案 4 :(得分:1)
u07ch,
不幸的是你不能使用保存事务并尝试..一起捕捉 - 它们根本无法一起工作:
答案 5 :(得分:1)
了解您在触发器中尝试做什么可能会有所帮助。
触发器是将数据发送到插入或删除表的事务的一部分。如果失败,它将回滚整个事务。如果您希望触发器偶尔失败但不回滚使触发器触发的语句,那么您可能需要重新考虑触发器是否正确使用。
答案 6 :(得分:1)
这不是最好的方式,但它有效。启动一个新事务并执行正常的提交回滚,并在最后开始另一个事务以进行隐式事务提交
http://msdn.microsoft.com/en-us/library/ms187844(v=SQL.90).aspx
答案 7 :(得分:1)
这个演示实现了上面提到的许多事情。错误消息变为可选。使它工作的技巧是在嵌套的动态执行中。
if object_id('toto') is not null drop table toto
go
create table toto (i int);
go
if object_id('toto2') is not null drop table toto2
go
create table toto2 (i int);
go
create Trigger trtoto
ON toto
Instead Of Insert
as
Begin
BEGIN TRY
set nocount on
insert into toto values(2)
declare @sql nvarchar(max) = 'insert into toto2 values(3); select * from ThisTableDoesntexist'
Exec sp_executeSql N'set xact_abort off; exec (@sql) ', N'@sql nvarchar(max)', @sql
END TRY
BEGIN CATCH
PRINT 'Error on line ' + CAST(ERROR_LINE() AS VARCHAR(10))
PRINT ERROR_MESSAGE()
END CATCH
End
GO
-- tests
set nocount on
insert into toto values (1) -- is not inserted on purpose by the trigger
select * from toto -- other value inserted despite the error
select * from toto2 -- other value inserted in other table despite the error
答案 8 :(得分:0)
您可以在触发开始时将XACT_Abort设置为OFF。