INSERT AFTER或UPDATE AFTER触发器内的回滚是否回滚整个事务

时间:2012-07-13 11:19:23

标签: sql-server sql-server-2008 tsql triggers

INSERT AFTER或UPDATE AFTER触发器内的回滚是否会回滚整个事务,或仅回滚触发原因的当前行,是否与Commit相同?

我试图通过我当前使用MSTDC进行交易的项目代码来检查它,看起来好像完整的交易已经中止。

如果触发器中的回滚确实回滚整个事务,是否有一种解决方法可以将其限制为仅当前行。

我在此找到了sybase的链接,但sql server上没有任何内容

3 个答案:

答案 0 :(得分:8)

是的,它会回滚整个交易。

全部在docs(见备注)。请注意我强调的评论 - 我会说这非常重要!!

  

如果在触发器中发出ROLLBACK TRANSACTION:

     

在当前交易中对该点进行的所有数据修改   被回滚,包括触发器产生的任何东西。

     

触发后继续执行任何剩余的语句   ROLLBACK声明。如果这些语句中的任何一个修改数据,那么   修改不会回滚。没有嵌套触发器被触发   执行这些剩余的陈述。

     

触发触发器的语句后批处理中的语句   没有执行。

答案 1 :(得分:1)

正如您已经知道的那样,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

同样,您需要检查更新语句(如果有)。

答案 2 :(得分:0)

任何回滚命令都会回滚所有内容,直到@@ trancount为0,除非你指定了一些保存点,并且无论你把rollback tran命令放在哪里都没关系。

最好的方法是再次查看代码并确认业务需求,看看为什么需要在触发器中回滚?