交易儲存點

儲存點 (Savepoint) 提供回復部分交易的機制。您可以使用 SAVE TRANSACTION savepoint_name 陳述式來建立儲存點。接著再執行 ROLLBACK TRANSACTION savepoint_name 陳述式回復到儲存點,而非回復到交易的起點。

不太可能發生錯誤時,儲存點特別有用。發生不常見的錯誤時,使用儲存點來回復部分交易,比在進行更新之前,測試每筆交易來查看是否可以更新要更為有效。更新與回復都是費時的動作,因此儲存點只有在遇到錯誤的可能性不高,且事前檢查更新可用性的成本相當高的情形下才有效率。

此範例顯示訂單系統中的儲存點使用範例,此系統由於公司的供應商與訂貨點充足,因此發生缺貨的可能性不高。應用程式通常會在嘗試進行記錄訂單的更新之前,先證實手邊的存貨已經足夠。基於某種原因,這個範例假設要事先驗證可用的存貨量是相當費時的 (由於使用低速數據機或 WAN 連接)。應用程式可以撰寫成僅進行更新,並於發生存貨不足的錯誤時回復更新。在這種情況下,插入資料之後快速檢查 @@ERROR 比更新之前驗證數量要快得多。

InvCtrl 資料表擁有 CHECK 條件約束,可在 QtyInStk 資料行降至 0 以下時觸發 547 的錯誤。OrderStock 程序可建立儲存點。如果發生 547 錯誤,便回復到儲存點,並將手邊的項目數量傳回呼叫的處理序 (Process)。然後呼叫的處理序便可取代手邊的訂單數量。如果 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