在存储过程和触发器中回滚和提交

可以在存储过程或触发器中执行 ROLLBACK TRANSACTION 或 COMMIT TRANSACTION Transact-SQL 语句,但这样可能会导致错误。

在存储过程中

如果 @@TRANCOUNT 的值在完成存储过程时与执行存储过程时不同,则会出现信息性错误 (266)。发生这种情况的方式有两种:

  • 用值为 1 或更大的 @@TRANCOUNT 调用存储过程,并且存储过程执行一条 ROLLBACK TRANSACTION 语句。当存储过程完成时,@@TRANCOUNT 减少为 0 并导致错误 266。

  • 用值为 1 或更大的 @@TRANCOUNT 调用存储过程,并且存储过程执行一条 COMMIT TRANSACTION 语句。当存储过程完成时,@@TRANCOUNT 减少 1 并导致错误 266。但是,如果在 COMMIT TRANSACTION 之后执行 BEGIN TRANSACTION,则不会出现此错误。

在触发器中

当执行触发器时,触发器的操作好像有一个未完成的事务在起作用。不管激发触发器的语句在隐式事务中还是显式事务中,都会这样。

当语句开始以自动提交模式执行时,如果遇到错误,可以通过隐式 BEGIN TRANSACTION 语句恢复该语句生成的所有修改。此隐式事务对批处理中的其他语句没有影响,因为当语句完成时,此事务要么提交,要么回滚。但是,当调用触发器时,此隐式事务仍然有效。

执行触发器时,将开始隐式事务。在执行完触发器后,如果 @@TRANCOUNT = 0,则会出现错误 3609 并终止批处理。如果在触发器中发出 BEGIN TRANSACTION 语句,则会创建一个嵌套事务。在这种情况下,执行 COMMIT TRANSACTION 语句时,该语句仅应用于嵌套事务。

在触发器使用 ROLLBACK TRANSACTION 时,请注意下列行为:

  • 当前事务中该时间点之前所做的所有数据修改都将回滚,包括触发器所做的修改。

  • 触发器继续执行 ROLLBACK 语句之后的所有语句。如果这些语句中的任意语句修改数据,则不回滚这些修改。

  • 触发器中的 ROLLBACK 关闭并释放所有在包含激发触发器的语句的批处理中声明和打开的游标。这包括在激发触发器的批处理所调用的存储过程中声明和打开的游标。在激发触发器的批处理之前的批处理中声明的游标只关闭。但是,STATIC 或 INSENSITIVE 游标在下列条件下不会关闭:

    • CURSOR_CLOSE_ON_COMMIT 设置为 OFF。

    • 静态游标是同步游标或者完全填充的异步游标。

可以不使用 ROLLBACK TRANSACTION,而使用 SAVE TRANSACTION 语句在触发器中执行部分回滚。