INSERT AFTER 或 UPDATE AFTER 触发器内的回滚是回滚整个事务还是仅回滚作为触发原因的当前行,它与 Commit 相同吗?
我试图通过我当前使用 MSTDC 进行事务的项目代码来检查它,看起来好像整个事务被中止了。
如果触发器中的回滚确实回滚了整个事务,是否有一种解决方法可以将其限制为仅当前行。
我在此找到了sybase的链接,但在 sql server 上没有
INSERT AFTER 或 UPDATE AFTER 触发器内的回滚是回滚整个事务还是仅回滚作为触发原因的当前行,它与 Commit 相同吗?
我试图通过我当前使用 MSTDC 进行事务的项目代码来检查它,看起来好像整个事务被中止了。
如果触发器中的回滚确实回滚了整个事务,是否有一种解决方法可以将其限制为仅当前行。
我在此找到了sybase的链接,但在 sql server 上没有
是的,它将回滚整个事务。
这一切都在文档中(请参阅备注)。请注意我强调的评论 - 我会说这非常重要!
如果在触发器中发出 ROLLBACK TRANSACTION:
在当前事务中对该点所做的所有数据修改都会回滚,包括触发器所做的任何修改。
触发器在 ROLLBACK 语句之后继续执行任何剩余的语句。如果这些语句中的任何一个修改了数据,则修改不会回滚。执行这些剩余语句不会触发嵌套触发器。
在触发触发器的语句之后的批处理中的语句不会被执行。
正如您已经知道的那样,ROLLBACK 命令不可能被修改/调整,以便它只回滚触发器发出的语句。
如果您确实需要一种方法来“回滚”仅由触发器执行的操作,作为一种解决方法,您可以考虑修改您的触发器,以便在执行操作之前,触发器确保这些操作不会产生异常情况会导致整个事务回滚。
例如,如果您的触发器插入行,请添加检查以确保新行不违反例如唯一约束(或外键约束),如下所示:
IF NOT EXISTS (
SELECT *
FROM TableA
WHERE … /* a condition to test if a row or rows you are about
to insert aren't going to violate any constraint */
)
BEGIN
INSERT INTO TableA …
END;
或者,如果您的触发器删除行,请检查它是否不尝试删除其他表引用的行(在这种情况下,您通常需要事先知道哪些表可能引用这些行):
IF NOT EXISTS (
SELECT * FROM TableB WHERE …
)
AND NOT EXISTS (
SELECT * FROM TableC WHERE …
)
AND …
BEGIN
DELETE FROM TableA WHERE …
END
同样,您需要检查更新语句(如果有)。
任何回滚命令都会回滚所有内容,直到 @@trancount 为 0,除非您指定了一些保存点,并且您将 rollback tran 命令放在哪里都没有关系。
最好的方法是再次查看代码并确认业务需求,看看为什么需要在触发器中回滚?