Por padrão, as Transações, na maioria das vezes, não são revertidas / canceladas automaticamente quando ocorre um erro. Isso geralmente não é um problema, desde que você tenha um tratamento de erros adequado e ligue para ROLLBACKsi mesmo. No entanto, às vezes as coisas ficam complicadas, como no caso de erros de interrupção de lote ou ao usar OPENQUERY(ou Servidores Vinculados em geral) e ocorre um erro no sistema remoto. Embora a maioria dos erros possa ser interceptada TRY...CATCH, existem dois que não podem ser interceptados dessa maneira (embora não se lembre de quais no momento - pesquisando). Nesses casos, você deve usar SET XACT_ABORT ONpara reverter corretamente a transação.
SET XACT_ABORT ON faz o SQL Server reverter imediatamente qualquer transação (se uma estiver ativa) e abortar o lote se ocorrer algum erro. Essa configuração existia antes do SQL Server 2005, que introduziu a TRY...CATCHconstrução. Na maioria das vezes, TRY...CATCHlida com a maioria das situações e, portanto, obsoleta a necessidade XACT_ABORT ON. No entanto, ao usar OPENQUERY(e possivelmente um outro cenário que não me lembro no momento), você ainda precisará usá-lo SET XACT_ABORT ON;.
Você sempre deve ter o tratamento de erros adequado, especialmente ao usar Transações. A TRY...CATCHconstrução, introduzida no SQL Server 2005, fornece um meio de lidar com quase todas as situações, uma melhoria bem-vinda sobre o teste @@ERRORapós cada instrução, o que não ajudou muito com erros de interrupção de lote.
TRY...CATCHintroduziu um novo "estado", no entanto. Quando nãoTRY...CATCH estiver usando a construção, se você tiver uma transação ativa e ocorrer um erro, existem vários caminhos que podem ser seguidos:
XACT_ABORT OFFe erro de cancelamento de instrução: a transação ainda está ativa e o processamento continua com a próxima instrução , se houver.
XACT_ABORT OFFe a maioria dos erros de interrupção de lote: a transação ainda está ativa e o processamento continua com o próximo lote , se houver.
XACT_ABORT OFFe certos erros de interrupção de lote: a transação é revertida e o processamento continua com o próximo lote , se houver.
XACT_ABORT ONe qualquer erro: a transação é revertida e o processamento continua com o próximo lote , se houver.
NO ENTANTO, ao usar TRY...CATCH, os erros de interrupção de lote não abortam o lote, mas transferem o controle para o CATCHbloco. Quando XACT_ABORTfor OFF, a Transação ainda estará ativa na grande maioria das vezes, e você precisará COMMIT, ou provavelmente ROLLBACK. Porém, ao encontrar certos erros de interrupção de lote (como com OPENQUERY), ou quando XACT_ABORTestiver ON, a Transação estará em um novo estado, "não comprometível". Nesse estado, você não pode COMMIT, nem pode executar operações DML. Tudo o que você pode fazer é ROLLBACKe SELECTdeclarações. No entanto, nesse estado "incompatível", a Transação foi revertida após o erro que ocorreu e emitir a ROLLBACKé apenas uma formalidade, mas que deve ser executada.
Uma função, XACT_STATE , pode ser usada para determinar se uma transação está ativa, incompatível ou não existe. Recomenda-se (por alguns, pelo menos) verificar esta função no CATCHbloco para determinar se o resultado é -1(ou seja, incompatível) em vez de testar se @@TRANCOUNT > 0. Mas com XACT_ABORT ON, esse deve ser o único estado possível, portanto parece que testar @@TRANCOUNT > 0e XACT_STATE() <> 0é equivalente. Por outro lado, quando XACT_ABORTexiste OFFe existe uma transação ativa, é possível ter um estado de um 1ou -1de um CATCHbloco, o que permite a possibilidade de emitir em COMMITvez de ROLLBACK(embora, não consigo pensar em um caso para quando alguém gostaria deCOMMITse a transação for confirmada). Mais informações e pesquisas sobre o uso XACT_STATE()em um CATCHbloco XACT_ABORT ONpodem ser encontradas na minha resposta à seguinte pergunta do DBA.SE: Em que casos uma transação pode ser confirmada de dentro do bloco CATCH quando XACT_ABORT está definido como ON? . Observe que há um pequeno erro XACT_STATE()que faz com que ele retorne falsamente 1em certos cenários: XACT_STATE () retorna 1 quando usado em SELECT com algumas variáveis do sistema, mas sem a cláusula FROM
spNewBilling3gera um erro, mas você não deseja reverterspNewBilling2ouspNewBilling1, basta remover[begin|rollback|commit] transaction createSavebillinginvoicedespSavesomename.