Pontos de salvamento de transação

Os pontos de salvamento oferecem um mecanismo para reverter partes de transações. Você cria um ponto de salvamento usando a instrução SAVE TRANSACTION savepoint_name. Posteriormente, você executa uma instrução ROLLBACK TRANSACTION savepoint_name para reverter ao ponto de salvamento em vez de reverter ao início da transação.

Os pontos de salvamento são úteis em situações onde erros são improváveis. O uso de um ponto de salvamento para reverter parte de uma transação na ocorrência de um erro não frequente pode ser mais eficiente do que testar cada transação para verificar se uma atualização é válida antes de fazer a atualização. As atualizações e reversões são operações caras, portanto, pontos de salvamento só serão eficientes se a probabilidade de encontrar o erro for baixa e o custo de verificar a validade de uma atualização com antecedência for relativamente alto.

Este exemplo mostra o uso de um ponto de salvamento em um sistema de pedidos no qual há uma baixa probabilidade de falta de estoque porque a companhia tem fornecedores efetivos e pontos de novos pedidos. Normalmente, um aplicativo verificaria se há estoque suficiente disponível antes de tentar fazer as atualizações que registrariam o pedido. Esse exemplo presume que, por alguma razão, verificar a quantidade de estoque disponível com antecedência é relativamente caro (devido à conexão com um modem lento ou WAN). O aplicativo poderia ser codificado apenas para fazer a atualização, e se ele recebesse um erro que indicasse que não há estoque suficiente, ele reverteria a atualização. Nesse caso, uma verificação rápida de @@ERROR após a inserção é muito mais rápida do que verificar a quantia antes da atualização.

A tabela InvCtrl tem uma restrição CHECK que engatilha um erro 547 se a coluna QtyInStk estiver abaixo de 0. O procedimento OrderStock cria um ponto de salvamento. Se um erro 547 ocorrer, ele será revertido ao ponto de salvamento e retornará o número de itens disponíveis para o processo de chamada. Depois, o processo de chamada pode substituir o pedido para a quantidade disponível. Se OrderStock retornar 0, isso confirma ao processo de chamada que havia estoque suficiente para atender o pedido.

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