【问题标题】:What is the right way to use multiple savepoints使用多个保存点的正确方法是什么
【发布时间】:2015-05-11 15:27:33
【问题描述】:

我是第一次使用事务,所以我可能会问一个愚蠢的问题。

我想在 3 个表中插入数据:

Table1(p1,p2,p3)
Table2(q1,q2)
Table3(t3,fk1,fk2)

例如,如果出现问题并且无法将数据插入Table2,则来自Table1 的数据不会丢失并且Table3 保持不变(反之亦然)。

到目前为止,我已经尝试了两个版本,但没有一个令人满意。

版本 1:

CREATE PROCEDURE InsertInto(@p1,@p2,@p3,@q1,@q2,@t3))
AS BEGIN

BEGIN TRAN
SET XACT_ABORT OFF

SAVE TRANSACTION point1
BEGIN TRY
    DECLARE @fk1 INT
    INSERT INTO Table1 VALUES (@p1,@p2,@p3)
    SELECT @fk1 = Table1.Id FROM Table1 WHERE Table1.p1 = @p1

    SAVE TRANSACTION point2
    BEGIN TRY
        DECLARE @fk2 INT
        INSERT INTO Table2 VALUES (@q1,@q2)
        SELECT @fk2 = Table2.Id FROM Table2 WHERE Table2.q1 = @q1

        SAVE TRANSACTION point3
        BEGIN TRY
            INSERT INTO Table3 VALUES (@t3, @fk1, @fk2)
            COMMIT TRAN
            END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION point3
            COMMIT TRAN
        END CATCH
        
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION point2
        COMMIT TRAN
    END CATCH

END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point1
    COMMIT TRAN
END CATCH
END

但是如果不能在Table1 中插入数据,那么Table2 的可能数据就会丢失,我不想丢失任何东西。所以,我尝试了拆分它。

版本 2:

CREATE PROCEDURE InsertInto(@p1,@p2,@p3,@q1,@q2,@t3)
AS
BEGIN

BEGIN TRAN
SET XACT_ABORT OFF

SAVE TRANSACTION point1
BEGIN TRY
    DECLARE @fk1 INT
    INSERT INTO Table1 VALUES (@p1,@p2,@p3)
    SELECT @fk1 = Table1.Id FROM Table1 WHERE Table1.p1 = @p1
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point1
    COMMIT TRAN
END CATCH

SAVE TRANSACTION point2
BEGIN TRY
    DECLARE @fk2 INT
    INSERT INTO Table2 VALUES (@q1,@q2)
    SELECT @fk2 = Table2.Id FROM Table2 WHERE Table2.q1 = @q1
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point2
    COMMIT TRAN
END CATCH

SAVE TRANSACTION point3
BEGIN TRY
    INSERT INTO Table3 VALUES (@t3,@fk1,@fk2)
    COMMIT TRAN
 END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION point3
    COMMIT TRAN
 END CATCH
END

但如果插入 Table2 失败,我会得到:

(受影响的 1 行)

(0 行受影响)
消息 628,级别 16,状态 0,过程 InsertInto,第 26 行(第二个 BEGIN CATCH)
没有活动事务时无法发出 SAVE TRANSACTION。

我怎样才能做到这一点?

【问题讨论】:

  • 这里似乎根本不应该使用保存点,而只是在每一步之后提交,然后开始一个新事务。你能澄清你为什么使用保存点吗?也许您的代码的某些用途只是从问题中不清楚。
  • 我想学习如何使用保存点,以免在事务期间丢失数据。

标签: sql sql-server transactions savepoints


【解决方案1】:

SAVE TRAN 要求事务计数 > 0,因此您必须在前一个 CATCH 块中提交您的事务。您有多种选择:

1) 将您的 SAVE TRAN 语句替换为以下内容(您可以使用相同的保存点名称,但是回滚只会回滚到最后一个保存点):

IF @@TRANCOUNT = 0
    BEGIN TRAN;
ELSE
    SAVE TRAN tran1;

2) 在 CATCH 块中,在 COMMIT TRAN 之后添加 BEGIN TRAN

BEGIN CATCH
    ROLLBACK TRANSACTION point1
    COMMIT TRAN
    BEGIN TRAN
END CATCH

3) 删除 CATCH 块中的所有 COMMIT TRAN,并在最后执行一次 COMMIT。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    相关资源
    最近更新 更多