我第一次使用交易,所以我可能会问一个愚蠢的问题。
我想在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。
我该怎么做?
答案 0 :(得分:1)
SAVE TRAN需要交易次数>因此,您必须已在先前的CATCH块中提交了您的事务。您有几种选择:
1)用以下内容替换您的SAVE TRAN语句(您可以使用相同的保存点名称,但回滚只会回滚到最后一个保存点):
IF @@TRANCOUNT = 0
BEGIN TRAN;
ELSE
SAVE TRAN tran1;
2)在CATCH块中,在COMMIT TRAN
之后添加BEGIN TRANBEGIN CATCH
ROLLBACK TRANSACTION point1
COMMIT TRAN
BEGIN TRAN
END CATCH
3)删除CATCH块内的所有COMMIT TRAN,并在最后执行一次COMMIT。