Точки сохранения транзакции
Точки сохранения предоставляют механизм отката части транзакций. Для создания точек сохранения служит инструкция SAVE TRANSACTION savepoint_name. Затем при помощи инструкции ROLLBACK TRANSACTION savepoint_name транзакцию можно откатить не до начала, а только до точки сохранения.
Точки сохранения удобно использовать, когда вероятность возникновения ошибок мала. Откат до точки сохранения в ситуации, когда ошибка встречается крайне редко, часто более эффективен, чем подход, когда каждая транзакция проверяет допустимость обновления, прежде чем его выполнить. Операции обновления и отката являются ресурсоемкими, поэтому точки сохранения приносят пользу, только если вероятность ошибок небольшая, а затраты на проверку допустимости обновления относительно высокие.
Следующий пример демонстрирует использование точки сохранения в системе заказов, где вероятность отсутствия товаров на складе крайне мала, поскольку компания работает с хорошими поставщиками и пунктами повторного заказа. Обычно приложение должно проверять наличие товара на складе, прежде чем принять заказ. В этом примере предполагается, что по каким-то причинам проверка наличия товара на складе — относительно дорогая операция (например из-за соединения по медленной модемной линии или глобальной сети). Приложение можно построить таким образом, чтобы оно выполняло обновление и при возникновении ошибки (товар отсутствует на складе) откатывало его назад. В этом случае быстрая проверка параметра @@ERROR после вставки строки может выполняться значительно быстрее, чем проверка количества товара перед обновлением.
Таблица InvCtrl имеет ограничение CHECK, которое вызывает ошибку 547, если значение в столбце QtyInStk становится меньше 0. Процедура OrderStock создает точку сохранения. При возникновении ошибки 547 она откатывает транзакцию до точки сохранения и возвращает оставшееся количество товаров вызывающему процессу. После этого вызывающий процесс может принять заказ на имеющееся количество товара. Если процедура OrderStock возвращает 0, вызывающий процесс понимает, что на складе имеется достаточное количество товаров.
SET NOCOUNT OFF;
GO
USE AdventureWorks2008R2;
GO
CREATE TABLE InvCtrl
(WhrhousID int,
PartNmbr int,
QtyInStk int,
ReordrPt int,
CONSTRAINT InvPK PRIMARY KEY
(WhrhousID, PartNmbr),
CONSTRAINT QtyStkCheck CHECK (QtyInStk > 0) );
GO
CREATE PROCEDURE OrderStock
@WhrhousID int,
@PartNmbr int,
@OrderQty int
AS
DECLARE @ErrorVar int;
SAVE TRANSACTION StkOrdTrn;
UPDATE InvCtrl SET QtyInStk = QtyInStk - @OrderQty
WHERE WhrhousID = @WhrhousID
AND PartNmbr = @PartNmbr;
SELECT @ErrorVar = @@error;
IF (@ErrorVar = 547)
BEGIN
ROLLBACK TRANSACTION StkOrdTrn;
RETURN (SELECT QtyInStk
FROM InvCtrl
WHERE WhrhousID = @WhrhousID
AND PartNmbr = @PartNmbr);
END
ELSE
RETURN 0;
GO