Transações no SQL Server: do básico ao XACT_ABORT, TRY…CATCH e níveis de isolamento


Introdução
Transações são a base da integridade em bancos de dados. Quando bem definidas, garantem as propriedades ACID: Atomicidade, Consistência, Isolamento e Durabilidade. Neste guia prático você verá, na prática, os tipos de transação no SQL Server (autocommit, implícita e explícita), como evitar commits “parciais” com XACT_ABORT
, como tratar erros corretamente com TRY…CATCH
, RAISERROR
e THROW
, além de entender os impactos de isolamento/concorrência e por que leituras “sem bloqueio” exigem critério.
Ambiente de demonstração
A tabela a seguir será usada em todos os exemplos:
DROP TABLE IF exists Funcionario
go
CREATE TABLE Funcionario (PK int primary key, Nome varchar(50), Descricao varchar(100), [Status] char(1),Salario decimal(10,2))
INSERT Funcionario VALUES (1,'Fernando','Gerente','B',5600.00)
INSERT Funcionario VALUES (2,'Ana Maria','Diretor','A',7500.00)
INSERT Funcionario VALUES (3,'Lucia','Gerente','B',5600.00)
INSERT Funcionario VALUES (4,'Pedro','Operacional','C',2600.00)
INSERT Funcionario VALUES (5,'Carlos','Diretor','A',7500.00)
INSERT Funcionario VALUES (6,'Carol','Operacional','C',2600.00)
INSERT Funcionario VALUES (7,'Luana','Operacional','C',9600.00)
INSERT Funcionario VALUES (8,'Paulo','Diretor','A',7500.00)
INSERT Funcionario VALUES (9,'Erick','Operacional','C',2600.00)
INSERT Funcionario VALUES (10,'Joana','Operacional','C',2600.00)
go
1) Tipos de transações
1.1 Autocommit (automáticas)
Cada instrução é uma transação independente; se não ocorrer erro, o commit é automático. Observe que ROLLBACK
isolado não desfaz o UPDATE
anterior, pois não há transação aberta:
-- Autocommit
UPDATE Funcionario SET Salario = 9300.00 WHERE PK = 2; -- valor original 7500
ROLLBACK; -- não tem efeito aqui
-- Em outra conexão, verifique:
SELECT * FROM Funcionario WHERE PK = 2;
1.2 Transações implícitas
Ao ativar SET IMPLICIT_TRANSACTIONS ON
, o SQL Server passa a abrir uma transação implicitamente na primeira instrução DML de cada “lote” de ações — e você precisa dar COMMIT
ou ROLLBACK
.
SET IMPLICIT_TRANSACTIONS ON;
UPDATE Funcionario SET Salario = 9000.00 WHERE PK = 5; -- 7500
UPDATE Funcionario SET Salario = 5300.00 WHERE PK = 6; -- 2600
ROLLBACK;
-- Em outra conexão:
SELECT * FROM Funcionario WHERE PK = 5;
SELECT * FROM Funcionario WHERE PK = 6;
SELECT * FROM Funcionario WHERE PK = 10;
SET IMPLICIT_TRANSACTIONS OFF;
1.3 Transações explícitas
Sem tratamento de erro, é fácil “commitar pela metade”. Abaixo, o UPDATE
executa, o INSERT
falha (chave primária duplicada) e, se você der COMMIT
depois, confirmará apenas o que deu certo — péssimo para integridade:
-- Transação explícita SEM tratamento de erro
SELECT * FROM Funcionario WHERE PK IN (9,10);
SELECT @@TRANCOUNT;
BEGIN TRAN;
UPDATE Funcionario SET Salario = 3000.00 WHERE PK = 9; -- 2600
INSERT Funcionario VALUES (10,'Joana','Operacional','C',2600.00); -- ERRO PK
COMMIT; -- ⚠️ confirma o UPDATE, embora o INSERT tenha falhado
2) Evite commits parciais com XACT_ABORT
Quando XACT_ABORT
está ON
, qualquer erro de tempo de execução aborta toda a transação automaticamente com rollback — ideal para garantir atomicidade em blocos críticos. Contudo toda a transação precisa estar no mesmo Batch!
SELECT * FROM Funcionario WHERE PK IN (9,10);
SELECT @@TRANCOUNT;
SET XACT_ABORT ON;
BEGIN TRAN;
UPDATE Funcionario SET Salario = 8500.00 WHERE PK = 9; -- 3000
INSERT Funcionario VALUES (10,'Joana','Operacional','C',2600.00); -- ERRO PK
COMMIT;
SET XACT_ABORT OFF;
Mes cuidado, Nem todos os erros disparam rollback automático
XACT_ABORT ON
funciona apenas para erros de tempo de execução (runtime errors), como violação de chave primária, divisão por zero, truncamento de dados etc.Já erros de compilação (syntax error, coluna inexistente, etc.) não são afetados, pois a transação nem chega a ser executada.
Também há exceções conhecidas, como alguns erros de constraint deferred ou warnings que não abortam a transação.
Dentro de triggers, dependendo da operação,
XACT_ABORT
pode não funcionar como esperado, pois o contexto transacional é herdado da operação que disparou a trigger.
3) Tratamento de erros profissional: TRY…CATCH
, RAISERROR
e THROW
3.1 TRY…CATCH com transações
Padrão recomendável: abrir a transação dentro do TRY
, e no CATCH
sempre checar @@TRANCOUNT
para garantir o ROLLBACK
se algo falhar:
SELECT * FROM Funcionario WHERE PK IN (8,10);
BEGIN TRY
BEGIN TRAN;
UPDATE Funcionario SET Salario = 9000.00 WHERE PK = 8; -- 7500
INSERT Funcionario VALUES (10,'Joana','Operacional','C',2600.00); -- ERRO PK
COMMIT;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
IF @@TRANCOUNT > 0
ROLLBACK;
END CATCH;
GO
3.2 Severidades
Para investigar e padronizar mensagens, você pode consultar master.sys.messages
e entender a gravidade (severity) dos erros:
SELECT * FROM master.sys.messages;
SELECT DISTINCT severity FROM master.sys.messages ORDER BY 1;
/*
<= 16 - Informativas
17 - Recursos esgotados (ex.: disco cheio ou blocking excessivo)
18–19 - Erros não fatais (conexão permanece)
20–24 - Erros fatais (derrubam a conexão)
*/
3.3 RAISERROR
Dentro do CATCH
, você pode levantar um aviso customizado (útil para logs/monitoramento) informando contexto do erro:
BEGIN TRY
SELECT 10/0 AS 'Provoca erro de divisão por zero.';
END TRY
BEGIN CATCH
DECLARE @Banco nvarchar(200) = DB_NAME();
RAISERROR (N'Erro de divisão por zero no Banco de Dados %s', 10, 1, @Banco);
END CATCH;
GO
3.4 THROW
Use THROW
para propagar o erro original ou para lançar um erro de aplicativo (por exemplo, código 51000) com mensagem clara:
-- Repassa o erro original:
BEGIN TRY
SELECT 10/0;
END TRY
BEGIN CATCH
THROW;
END CATCH;
GO
-- Lança um erro específico:
BEGIN TRY
SELECT 10/0;
END TRY
BEGIN CATCH
DECLARE @Erro nvarchar(200) = N'Erro de divisão por zero no Banco de Dados ' + DB_NAME();
;THROW 51000, @Erro, 1;
END CATCH;
4) Concorrência e isolamento: o que considerar
Por padrão (READ COMMITTED), quem escreve bloqueia quem lê e vice-versa: durante um UPDATE
, um SELECT
concorrente fica em blocking até a liberação do lock. É seguro para os dados, porém pode reduzir a escalabilidade sob alta concorrência.
WITH (NOLOCK)
/READ UNCOMMITTED
eliminam o lock de leitura, mas abrem espaço para leitura suja (dirty read): você pode ler um valor que nunca será persistido se a outra transação fizer rollback. Só use com plena consciência das regras de negócio. Alternativamente, o snapshot isolation (com versionamento de linha) permite leitura sem bloqueio entregando o último valor confirmado — ótimo para relatórios/consultas — mas exige habilitação no banco e análise de impacto pelo DBA.
Deadlocks não são a mesma coisa que blocking: são ciclos de dependência sem saída; o SQL Server escolhe uma vítima (a de menor “custo” para desfazer) e a aborta para liberar o caminho. Boas práticas de acesso ordenado aos recursos e índices adequados ajudam a mitigá-los.
5) Boas práticas resumidas
Padronize: em código transacional, use
TRY…CATCH
+@@TRANCOUNT
e considereXACT_ABORT ON
.Seja explícito sobre isolamento: padrão (READ COMMITTED) é seguro; snapshot ajuda relatórios; evite
NOLOCK
como “padrão da casa”.Teste em concorrência: valide comportamento sob carga (leituras repetidas, transações longas, etc.).
Monitore: mensagens de erro, severidades e contadores de locking/waits ajudam a diagnosticar gargalos.
Conclusão
Com uma estratégia clara — transações bem definidas, tratamento de erro robusto e isolamento adequado — você garante integridade e previsibilidade sem abrir mão de desempenho. Use os blocos de código deste artigo como ponto de partida para padronizar suas rotinas T-SQL.
Fui, mas volto com mais SQL Server em breve!
✍️ Sobre o autor
O Prof. Landry é especialista em Microsoft SQL Server desde 1999, Microsoft Trainer, Professor Universitário e criador do canal SQL Server Expert no YouTube, com conteúdo técnico semanal para DBAs e profissionais de dados.
🚀 Quer aprender mais sobre SQL Server?
👉 Me acompanhe no LinkedIn e inscreva-se no canal para não perder nenhuma dica prática!
Subscribe to my newsletter
Read articles from SQL Server Expert directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

SQL Server Expert
SQL Server Expert
O Prof. Landry Duailibe é especialista em Microsoft SQL Server desde 1999, Microsoft Certified Trainer, professor universitário e criador do canal SQL Server Expert no YouTube, onde compartilha conteúdo técnico semanal para DBAs e profissionais de dados. Já ajudou milhares de alunos a evoluírem suas habilidades com SQL Server e conquistarem melhores oportunidades na área de dados.