0

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

我想在 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 行受影响)
消息 628,级别 16,状态 0,过程 InsertInto,第 26 行(第二个 BEGIN CATCH)
当没有活动事务时无法发出 SAVE TRANSACTION。

我怎样才能做到这一点?

4

1 回答 1

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。

于 2015-05-11T22:21:14.467 回答