代码之家  ›  专栏  ›  技术社区  ›  Gary McGill

如何避免在嵌套存储过程的嵌套事务中使用重复的保存点名称?

  •  4
  • Gary McGill  · 技术社区  · 16 年前

    我有一个几乎总是遵循的模式,如果我需要在事务中包装一个操作,我会这样做:

    BEGIN TRANSACTION
    SAVE TRANSACTION TX
    
    -- Stuff
    
    IF @error <> 0
        ROLLBACK TRANSACTION TX
    
    COMMIT TRANSACTION
    

    在过去,这对我来说已经足够好了,但是在多年使用这种模式(并复制粘贴上面的代码)之后,我突然发现了一个完全震惊的缺陷。

    CREATE TABLE Test (test INTEGER NOT NULL)
    
    BEGIN TRAN 
    SAVE TRAN TX
    
        BEGIN TRAN
        SAVE TRAN TX
            INSERT INTO Test(test) VALUES (1)
        COMMIT TRAN TX
    
        BEGIN TRAN
        SAVE TRAN TX
            INSERT INTO Test(test) VALUES (2)
        COMMIT TRAN TX
    
        DELETE FROM Test
    
    ROLLBACK TRAN TX
    COMMIT TRAN TX
    
    SELECT * FROM Test
    
    DROP TABLE Test
    

    当我执行这个时,它列出了一条记录,值为“1”。换句话说, 即使我回滚了我的外部事务 ,表中添加了一条记录。

    发生的事情是 ROLLBACK TRANSACTION TX 最外面的一层正在倒退到最后一层 SAVE TRANSACTION TX 在内部层面。现在我把这些都写出来了,我可以看到它背后的逻辑:服务器通过日志文件回溯,将其视为线性事务流;它不理解事务嵌套(或者在我的实际场景中,通过调用其他存储过程)所隐含的嵌套/层次结构。

    可以

    每次启动一个事务时,都要给出一个唯一的名称并不难(可以基于SP名称,或者类似的名称),但我确实担心最终会出现冲突—而且您不会知道,因为它不会导致错误,而是默默地销毁您的数据……:-(

    2 回复  |  直到 16 年前
        1
  •  2
  •   KM.    16 年前

    SAVE TRANSACTION (Transact-SQL)

    SAVE { TRAN | TRANSACTION } { savepoint_name | @savepoint_variable }
    [ ; ]
    

    DECALRE @savepoint_variable varchar(1000)
    SET @savepoint_variable=OBJECT_NAME(@@PROCID)+'|'+CONVERT(char(23),GETDATE(),121)
    
    BEGIN TRANSACTION
    SAVE TRANSACTION @savepoint_variable
    
    -- Stuff
    
    IF @error <> 0
    BEGIN
        ROLLBACK TRANSACTION @savepoint_variable
    END
    
    COMMIT TRANSACTION
    

    当从不同的过程调用时,@savepoint\u变量将具有不同的局部值,回滚应该回滚正确的值。我将当前日期时间放在保存点名称中,因为您可能会在某个点使用递归,如果这是复制粘贴模式,最好处理所有情况。

        2
  •  3
  •   etliens    16 年前

    同意KM的解决方案。

    DECLARE @savepoint AS VARCHAR(36)
    SET @savepoint = CONVERT(VARCHAR(36), NEWID())
    
    BEGIN TRANSACTION
    SAVE TRANSACTION @savepoint
    ...
    
    ROLLBACK TRANSACTION @savepoint
    COMMIT TRANSACTION