使用多个保存点的正确方法是什么
What is the right way to use multiple savepoints
我是第一次使用交易,所以我可能会问一个愚蠢的问题。
我想在 3 个表中插入数据:
Table1(p1,p2,p3)
Table2(q1,q2)
Table3(t3,fk1,fk2)
例如,如果出现问题,数据无法插入Table2
,Table1
的数据不会丢失,Table3
保持不变(反之亦然)。
到目前为止,我已经尝试了两个版本,但 none 令人满意。
版本 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 row(s) affected)
(0 row(s) affected)
Msg 628, Level 16, State 0, Procedure InsertInto, Line 26 (second BEGIN CATCH)
Cannot issue SAVE TRANSACTION when there is no active transaction.
我该怎样做才对?
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。
我是第一次使用交易,所以我可能会问一个愚蠢的问题。
我想在 3 个表中插入数据:
Table1(p1,p2,p3)
Table2(q1,q2)
Table3(t3,fk1,fk2)
例如,如果出现问题,数据无法插入Table2
,Table1
的数据不会丢失,Table3
保持不变(反之亦然)。
到目前为止,我已经尝试了两个版本,但 none 令人满意。
版本 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 row(s) affected)
(0 row(s) affected)
Msg 628, Level 16, State 0, Procedure InsertInto, Line 26 (second BEGIN CATCH)
Cannot issue SAVE TRANSACTION when there is no active transaction.
我该怎样做才对?
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。