使用多个保存点的正确方法是什么

时间:2015-05-11 15:27:34

标签: sql sql-server transactions savepoints

我第一次使用交易,所以我可能会问一个愚蠢的问题。

我想在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

但是如果Insert into Table2失败了,我明白了:

  

(1行受影响)

     

(0行(s)受影响)
   Msg 628,Level 16,State 0,Procedure InsertInto,Line 26(second BEGIN CATCH)
   没有活动交易时,无法发出SAVE TRANSACTION。

我该怎么做?

1 个答案:

答案 0 :(得分:1)

SAVE TRAN需要交易次数>因此,您必须已在先前的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。