关于SQL Server中嵌套事务的建议

3
我有一些“基本操作”存储过程,例如BookAVehicleUnBookAVehicle。它们都位于一个事务中。
但现在我需要一个稍微复杂一些的存储过程:RescheduleBooking。它也需要进行事务处理。
现在,在ResceduleBooking中,我想要调用BookAVehicle,但这种情况下,我不希望内部事务回滚。
但是当我直接调用BookAVehicle时,我想要保留回滚。
有什么优雅的建议吗?
我考虑了一些类似于“包装器”存储过程的东西,该存储过程作为参数获取一个存储过程的名称,并仅包含事务和对参数存储过程的调用。
所以当我“直接”调用它时,我会这样调用:
TransactionWrapper(BookAVehicleWithoutTrans)

当我从另一个事务中调用它时,我会这样调用:

RescheduleBooking -> BookAVehicleWithoutTrans

这是一个小小的秘密:SQL Server 似乎 支持嵌套事务 - 但实际上并不支持。这对开发人员来说有点像“眼药水” - 如果你在嵌套事务中回滚,所有当前正在运行的事务都将被回滚。请参见 Paul Randal 的 SQL Server DBA 每日神话帖子 上关于该主题的内容。 - marc_s
3
可能是 Nested stored procedures containing TRY CATCH ROLLBACK pattern? 的重复问题,这个链接来自@marc_s,处理了包含TRY CATCH回滚模式的嵌套存储过程,无论嵌套多少层都可以维护事务一致性。 - gbn
谢谢,看起来完全符合要求。 - barnonline
marc_s,我知道嵌套事务的回滚,如果我的帖子中没有表达清楚,我很抱歉。 - barnonline
1个回答

1
当您执行 BEGIN TRANSACTION 时,内部计数器会增加 @@TRANCOUNT。ROLLBACK TRANSACTION 将回滚所有 BEGIN TRANSACTIONS 并将 @@TRANCOUNT 设置为 0。在将 @@TRANCOUNT 设置为 0 之前,仅在 @@TRANCOUNT 为 1 时提交事务才会减少 @@TRANCOUNT 并进行完全提交。

考虑到这一点,假设您在 Book 和 UnBook 程序中配对了 BEGIN 和 COMMIT TRANSACTIONS,我会像以下代码一样编写 RescheduleBooking 程序,即使取消预订失败也会保留第一次预订...

CREATE PROCEDURE RescheduleBooking ...
AS
BEGIN
      BEGIN TRY
         BEGIN TRANSACTION
         EXEC BookAVehicle ...
         COMMIT TRANSACTION
      END TRY
      BEGIN CATCH
         IF @@TRANCOUNT > 0
         BEGIN
             ROLLBACK TRANSACTION
         END
         RETURN
      END CATCH;

   -- If the unbook fails the booking above will still stay.
      BEGIN TRY
         BEGIN TRANSACTION
         EXEC UnBookAVehicle ...
         COMMIT TRANSACTION
      END TRY
      BEGIN CATCH
         IF @@TRANCOUNT > 0
         BEGIN
             ROLLBACK TRANSACTION
         END
         RETURN
      END CATCH;
END

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接