2015-05-11 2 views
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 

Но если Вставить в терпит неудачу Table2, я получаю это:

(1 строка (ы) пострадавших)

(0 строк (ы) пострадавших)
Msg 628, уровень 16, состояние 0, процедура InsertInto, строка 26 (второй BEGIN CATCH)
Невозможно выдавать SAVE TRANSACTION, когда нет активных транзакций на.

Как я могу это сделать правильно?

+0

Кажется, что вы не должны использовать точки сохранения вообще здесь, а просто фиксируете после каждого шага, а затем начинаете новую транзакцию. Можете ли вы объяснить, почему вы используете точки сохранения? Возможно, некоторое использование вашего кода просто непонятно из вопроса. – hvd

+0

Я хочу узнать, как использовать точки сохранения, чтобы я не терял данные во время транзакции. – user1012732

ответ

1

SAVE TRAN требует транзакционного счета> 0, таким образом, вы должны были совершить транзакцию в предыдущем блоке CATCH. У вас есть несколько вариантов:

1) Заменить заявление SAVE TRAN следующего (вы можете использовать то же имя точки сохранения, однако откат будет откат только к последней точке сохранения):

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

2) блок уЛОВА, добавьте TRAN возможно записи после COMMIT TRAN

BEGIN CATCH 
    ROLLBACK TRANSACTION point1 
    COMMIT TRAN 
    BEGIN TRAN 
END CATCH 

3) Удалить все COMMIT TRAN внутри улова блоков, и делает один COMMIT в конце.

Смежные вопросы