Transações com COMMIT e ROLLBACK
Se você já trabalhou com um banco de dados relacional, sabe o que é uma transação e o quão importante ela é no banco de dados.
Então, você sabe que ao trabalhar com esse tipo de banco de dados, é essencial garantir a consistência e a integridade dos dados. Palavras bonitas, né?
O SQL fornece transações para lidar com operações que envolvem várias consultas. As transações nos permitem confirmar as alterações quando tudo ocorre bem ou revertê-las em caso de erros.
Este artigo explora as instruções DTL usando um esquema de banco de dados que criamos neste artigo sobre modelagem de dados.
Entendendo Transações
Você já ouviu falar sobre ACID? Tudo se resume a transações.
Uma transação é uma sequência de instruções SQL que são executadas como uma única unidade de trabalho. Ela segue as propriedades ACID:
- Atomicidade: Garante que todas as operações dentro de uma transação sejam concluídas com sucesso. Se uma falhar, toda a transação é revertida.
- Consistência: Assegura a integridade dos dados antes e depois da transação.
- Isolamento: Impede que transações interfiram umas nas outras.
- Durabilidade: Garante que, uma vez confirmada, a transação permaneça no banco de dados.
Comandos de Transação no SQL
- BEGIN TRANSACTION: Marca o início de uma transação.
- COMMIT: Salva todas as alterações feitas na transação.
- ROLLBACK: Desfaz todas as alterações caso ocorra um erro.
Trabalhando com Transações
O COMMIT
Vamos inserir um novo contato junto com objetivos e hábitos relacionados.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BEGIN TRANSACTION;
-- Insere novo contato
INSERT INTO [contacts] ([name], [surname], [email], [phone_number])
VALUES ('Lorenzo', 'Uriel', 'lorenzouriel@gmail.com', '1234567890');
-- Insere uma meta para o contato
INSERT INTO [goals] ([name], [description], [contact_id], [start], [end])
VALUES ('Read 10 Books', 'Complete reading 10 books this year', 2, '2025-01-01', '2025-12-31');
-- Insere uma hábito para o contato
INSERT INTO [habits] ([name], [description], [contact_id], [per_week], [per_month], [per_year])
VALUES ('Daily Exercise', 'Exercise for at least 30 minutes', 2, 5, 20, 240);
COMMIT;
- Se todas as instruções
INSERT
forem executadas com sucesso, oCOMMIT
vai salvar e finalizar a transação. - Se alguma instrução falhar, devemos garantir o uso de
ROLLBACK
para manter a integridade dos dados. Isso nos leva ao exemplo abaixo.
O ROLLBACK
Imagine que tentamos inserir dados, mas encontramos um erro.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
BEGIN TRANSACTION;
BEGIN TRY
-- Insere novo contato
INSERT INTO [contacts] ([name], [surname], [email], [phone_number])
VALUES ('Lorenzo', 'Uriel', 'lorenzouriel@gmail.com', '1234567890');
-- Erro intencional: definindo um contact_id incorreto (-1)
INSERT INTO [goals] ([name], [description], [contact_id], [start], [end])
VALUES ('Learn SQL', 'Master SQL in 6 months', -1, '2025-02-01', '2025-08-01');
COMMIT; -- Isso não será executado se ocorrer um erro
END TRY
BEGIN CATCH
-- Reverte a transação em caso de erro
ROLLBACK;
PRINT 'Transaction failed. All changes rolled back.';
END CATCH;
Neste exemplo:
- O
contact_id = -1
inválido causa uma violação de restrição de chave estrangeira. - O bloco
BEGIN CATCH
captura o erro e executaROLLBACK
. - Isso garante que nenhum dado parcial seja salvo.
Isto é o que acontece quando você executa:
Ainda não entendeu? Vamos analisar melhor este exemplo!
Analisando o Exemplo
1. BEGIN TRANSACTION
1
BEGIN TRANSACTION;
Isso inicia uma nova transação e o SQL Server marca este ponto no log de transações.
2. Bloco BEGIN TRY
1
2
3
BEGIN TRY
END TRY
Esse bloco garante que os erros sejam capturados e tratados corretamente. Então, se tudo for executado com sucesso, a transação será confirmada. Se ocorrer um erro, o controle será transferido para o bloco CATCH
.
3. Inserts (com erro intencional)
1
2
3
4
5
INSERT INTO [contacts] ([name], [surname], [email], [phone_number])
VALUES ('Lorenzo', 'Uriel', 'lorenzouriel@gmail.com', '1234567890');
INSERT INTO [goals] ([name], [description], [contact_id], [start], [end])
VALUES ('Learn SQL', 'Master SQL in 6 months', -1, '2025-02-01', '2025-08-01');
Todas essas operações não são imediatamente confirmadas, mas ficam no log de transações. A linha de inserção falha porque -1
é um contact_id
inválido. Devido à restrição de chave estrangeira em contact_id
, o SQL Server gera um erro.
4. COMMIT
1
COMMIT;
Esta linha nunca é executada porque o erro na etapa anterior transfere o controle para o bloco CATCH.
5. Bloco BEGIN CATCH
1
2
3
BEGIN CATCH
PRINT 'Transaction failed. All changes rolled back.';
END CATCH;
Aqui podemos tratar o erro, adicionando mensagens de PRINT
e a instrução ROLLBACK
. O SQL Server não confirma nenhuma alteração feita no bloco TRY
.
6. ROLLBACK
Transaction
1
ROLLBACK;
Desfaz todas as alterações feitas dentro da transação. Como o SQL Server segue o algoritmo de Write-Ahead Logging (WAL), ele pode reverter o banco de dados para seu estado anterior usando o log de transações.
Desde o início da transação, você não pode fazer um SELECT
na sua tabela devido a um lock gerado pela inicío da transação:
Até que o COMMIT
ou ROLLBACK
ocorra, a tabela ficará inacessível. Isso é ACID!
Perfeito! Este é um bom exemplo de como funciona e como pode salvar você em algumas situações.
Mas como isso funciona na camada de arquitetura?
Como as Transações Funcionam na Arquitetura do SQL Server
O SQL Server gerencia transações por meio do Transaction Manager, que garante as propriedades ACID (Atomicidade, Consistência, Isolamento, Durabilidade).
Aqui está como funciona internamente:
- O SQL Server grava todas as mudanças no log de transações (arquivo
LDF
) antes de fazer modificações no banco de dados real (arquivoMDF
). - Se uma transação for confirmada (
COMMIT
), as mudanças são gravadas permanentemente no disco. - Se uma transação falhar, o SQL Server usa o log para reverter as mudanças (via
ROLLBACK
), garantindo que o banco de dados volte ao seu estado anterior. - Durante o andamento da transação, o SQL Server aplica locks nas tabelas para evitar inconsistências de dados. Os níveis de isolamento controlam como as transações interagem entre si, garantindo que elas não interfiram umas nas outras.
–
Obrigado por ler até aqui!