CodeGym /Cursos /SQL SELF /Trabalhando com transações para garantir a integridade do...

Trabalhando com transações para garantir a integridade dos dados

SQL SELF
Nível 22 , Lição 2
Disponível

Bora imaginar que você tá criando um app pra uma loja online, e na hora de pagar o pedido você precisa:

  1. Reservar o dinheiro do cartão do cliente.
  2. Diminuir a quantidade do produto no estoque.
  3. Criar um registro da transação bem-sucedida.

E se no meio dessas ações alguma coisa der ruim? Tipo, o produto acaba no estoque depois que o dinheiro já foi reservado, mas antes de criar o registro do pedido? Vai dar ruim: o dinheiro fica "preso", o pedido não finaliza, e seu servidor recebe um monte de e-mails bravos (e talvez até processo).

Transações servem justamente pra evitar essas tretas. Elas deixam você agrupar várias operações numa só unidade "atômica" de trabalho com o banco de dados. Tipo aquele botão "Desfazer" do editor de texto: se algo deu errado, só voltar pro começo.

Como as transações garantem a integridade dos dados?

Transações são baseadas no conceito ACID:

  • Atomicidade (Atomicity) — Todas as operações dentro da transação rolam ou tudo junto, ou nada acontece. "Tudo ou nada".
  • Consistência (Consistency) — Os dados ficam consistentes antes e depois da transação.
  • Isolamento (Isolation) — Uma transação não atrapalha as outras.
  • Durabilidade (Durability) — Quando a transação termina, o resultado fica salvo mesmo se o sistema cair.

Por que eu tô repetindo isso? Porque esse é o ideal que todo mundo quer. E... que quase nunca rola 100%. Quando a gente voltar a falar de transações mais pra frente no curso, você vai ver que alguns princípios do ACID vão ter que ser sacrificados.

Então aproveita esse momento em que as transações parecem simples e lindas. Bora logo pros exemplos!

Exemplo de uso de transações

Bora ver um cenário de adicionar um estudante e registrar ele num curso.

Imagina que a gente tá mexendo num banco de dados de uma universidade. Agora temos ouvintes avulsos nos nossos cursos. Se tem vaga no curso, a gente registra esse ouvinte como estudante (temporário) e adiciona ele no curso. Olha como isso rola:

Ao adicionar um novo estudante no banco e registrar ele no curso, precisamos:

  1. Adicionar um registro na tabela students.
  2. Criar um registro na tabela enrollments, ligando o estudante ao curso.

Se algo der errado (tipo, o curso já tá lotado), a gente tem que desfazer tudo pra não deixar os dados bagunçados entre as tabelas. Olha só como faz:

-- Início da transação
BEGIN;

-- Passo 1: Adiciona o estudante
INSERT INTO students (name, age, gender)
VALUES ('Otto Lin', 20, 'Masculino')
RETURNING id;

-- Supondo que voltou id = 10

-- Passo 2: Registra ele no curso
INSERT INTO enrollments (student_id, course_id)
VALUES (10, 5);

-- Deu tudo certo? Salva as mudanças
COMMIT;

O que rola se der erro?

De repente deu erro ao registrar no curso: tipo, o curso não existe. Se você esquecer da transação, o registro do estudante vai ficar na tabela students, mas na tabela enrollments não. Isso quebra a integridade dos dados. Pra evitar isso, a gente pode usar o comando ROLLBACK.

-- Início da transação
BEGIN;

-- Passo 1: Adiciona o estudante
INSERT INTO students (name, age, gender)
VALUES ('Otto Lin', 20, 'Masculino')
RETURNING id;

-- Passo 2: Tenta registrar ele no curso
INSERT INTO enrollments (student_id, course_id)
VALUES (10, 999); -- Erro: não existe curso com id = 999!

-- Desfaz tudo
ROLLBACK;

No fim, nenhuma das operações vai acontecer, e o banco de dados fica igualzinho ao que tava antes da transação.

Usando SAVEPOINT pra controlar

Agora imagina um cenário mais complicado. Você quer fazer várias operações, mas em algum ponto precisa voltar só até um certo momento, não desfazer tudo.

Bora fazer um registro passo a passo do estudante

-- Início da transação
BEGIN;

-- Adiciona o estudante
SAVEPOINT add_student; -- Cria um ponto de salvamento
INSERT INTO students (name, age, gender)
VALUES ('Anna Song', 22, 'Feminino');

-- Registra ela no primeiro curso
SAVEPOINT enroll_course_1; -- Outro ponto de salvamento
INSERT INTO enrollments (student_id, course_id)
VALUES (11, 5);

-- Registra ela no segundo curso (aqui dá erro)
INSERT INTO enrollments (student_id, course_id)
VALUES (11, 999); -- Erro!

-- Volta só até o último ponto de salvamento
ROLLBACK TO enroll_course_1;

-- Continua o processo
INSERT INTO enrollments (student_id, course_id)
VALUES (11, 6);

-- Salva as mudanças
COMMIT;

Assim, erros numa parte do processo não atrapalham o resto dos dados.

Checando se teve alteração

Se uma query SQL muda alguma coisa, dá pra checar se realmente rolou alguma alteração ou não.

Pode acontecer de você rodar um DELETE, mas nenhuma linha bateu com o WHERE. Ou rodar um UPDATE, mas os dados já estavam iguais e nada mudou de verdade.

Pra isso existe uma variável de sistema especial chamada FOUND. Ela mostra se alguma linha foi afetada na última query SQL:

  • FOUND = TRUE — a query atualizou/deletou algo;
  • FOUND = FALSE — nada foi deletado ou alterado.

Com SELECT normal ela não funciona, só pra rastrear mudanças.

Na prática: processando pagamentos

Transações são super úteis em apps financeiros. Bora de novo pra um sistema que precisa transferir grana de uma conta pra outra.

-- Início da transação
BEGIN;

-- Passo 1: Tira dinheiro da primeira conta
UPDATE accounts
SET balance = balance - 100
WHERE id = 1 AND balance >= 100;

-- Passo 2: Checa se deu certo (linhas foram alteradas)
IF NOT FOUND THEN
    ROLLBACK; -- Desfaz se não tem saldo suficiente
    RAISE EXCEPTION 'Saldo insuficiente!'; -- Erro! Lança exceção
END IF;

-- Passo 3: Adiciona dinheiro na segunda conta
UPDATE accounts
SET balance = balance + 100
WHERE id = 2;

-- Salva a transação
COMMIT;

Aqui, se o cliente tentar transferir mais dinheiro do que tem, a transação é desfeita e o banco de dados não fica "travado".

Peculiaridades e erros comuns

Esqueceu o COMMIT: se você esquecer de rodar o COMMIT no fim da transação, o banco vai ficar "esperando" e as mudanças não vão ser salvas.

Esqueceu o WHERE: atualizar ou deletar dados sem condição pode dar ruim total. Tipo, DELETE FROM students sem WHERE apaga todos os estudantes.

Transações demoradas: se a transação fica aberta muito tempo, pode travar o acesso aos dados e ferrar a performance. Sempre finalize as transações (COMMIT ou ROLLBACK) o mais rápido possível.

Transações são seu melhor amigo quando o assunto é garantir integridade dos dados. Elas evitam inconsistências, principalmente em cenários complicados, tipo cadastro de usuários, processamento de pagamentos ou atualização de tabelas relacionadas. Mandando bem com BEGIN, COMMIT, ROLLBACK e SAVEPOINT, você vai criar apps mais seguros e confiáveis.

2
Tarefa
SQL SELF, nível 22, lição 2
Bloqueado
Noções básicas de uso de transações
Noções básicas de uso de transações
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION