6

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

我试图通过我当前使用 MSTDC 进行事务的项目代码来检查它,看起来好像整个事务被中止了。

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

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

4

3 回答 3

9

是的,它将回滚整个事务。

这一切都在文档中(请参阅备注)。请注意我强调的评论 - 我会说这非常重要!

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

在当前事务中对该点所做的所有数据修改都会回滚,包括触发器所做的任何修改。

触发器在 ROLLBACK 语句之后继续执行任何剩余的语句。如果这些语句中的任何一个修改了数据,则修改不会回滚。执行这些剩余语句不会触发嵌套触发器。

在触发触发器的语句之后的批处理中的语句不会被执行。

于 2012-07-13T11:31:39.463 回答
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

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

于 2012-07-16T05:38:53.293 回答
0

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

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

于 2012-07-13T13:37:10.030 回答