Triggers, transações e concorrência

Atomicidade, isolamento, bloqueios e integridade, com um contraexemplo de venda acima da lotação.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

Transação e invariante

Atomicidade confirma ou anula a unidade de trabalho inteira. Consistência depende das restrições e protocolo corretos; isolamento coordena efeitos concorrentes; durabilidade conserva confirmações segundo as garantias do sistema.

Reservar capacidade e inserir bilhete têm de pertencer à mesma transação. O contador livres deve coincidir com lotação menos bilhetes ativos em todos os caminhos de compra, cancelamento e alteração de lotação.

BEGIN;
UPDATE sessoes SET livres = livres - 1
WHERE id = 12 AND livres > 0 RETURNING id, livres;
-- Só inserir bilhete se o UPDATE devolveu uma linha.
-- Se devolveu zero, anular e responder "esgotado".
-- Inserir o bilhete antes de COMMIT.

Este é um protocolo a completar pela aplicação, não um script que confirma uma compra sozinho. Se a inserção falhar, ROLLBACK anula também o decremento. ROLLBACK TO SAVEPOINT só anula trabalho posterior ao ponto; colocar o ponto entre contador e bilhete pode deixar uma invariante quebrada.

Corrida pelo último lugar

Um trigger que conta bilhetes pode ver zero em duas transações, permitindo ambas inserir:

No Read Committed de PostgreSQL, o UPDATE condicional da mesma linha bloqueia o concorrente. Depois do COMMIT de A, B reavalia livres > 0 na versão atual e altera zero linhas. Se A anular, B pode reservar.

Alternativa: todos os escritores bloqueiam a sessão com SELECT ... FOR UPDATE antes de contar. Em Read Committed, conta numa instrução posterior à obtenção do bloqueio, com snapshot atualizado.

Isolamento e conflitos

Nível PostgreSQLGarantia relevante
Read UncommittedImplementado como Read Committed.
Read CommittedSnapshot por instrução; vê as próprias alterações e confirmações anteriores ao snapshot.
Repeatable ReadSnapshot estável; impede também phantoms em PostgreSQL, mas pode admitir write skew.
SerializableEfeitos compatíveis com uma ordem serial; pode abortar e exigir repetição completa.

Dirty read lê não confirmado; non-repeatable read encontra valor diferente numa releitura; phantom muda linhas do predicado. Write skew altera linhas distintas com base numa condição comum, como dois médicos retirarem simultaneamente os seus turnos.

Um deadlock é um ciclo de espera, não qualquer espera. Ordena a aquisição de recursos, encurta transações e prepara repetição segura das abortadas.

Triggers e rotinas

  • BEFORE pode alterar NEW; devolver NULL num trigger por linha pode suprimir a operação.
  • AFTER continua na transação, antes de COMMIT; o retorno por linha é ignorado.
  • INSTEAD OF substitui a operação, por exemplo numa vista.
  • ROW dispara por linha; STATEMENT por instrução, mesmo sem linhas afetadas.

NEW existe em INSERT, OLD em DELETE, ambos em UPDATE. UPDATE OF preco testa colunas mencionadas; IS DISTINCT FROM testa mudança real, incluindo NULL.

Função participa numa expressão; procedure usa CALL; trigger executa uma função de trigger. Funções também podem alterar dados. Controlo transacional em procedures depende do contexto permitido.

Usa INSERT ... RETURNING id, nunca MAX(id). currval é local à ligação após obter um valor da sequência. Sequências podem deixar lacunas após rollback. Emails e pagamentos externos precisam de protocolo próprio, pois ROLLBACK da base não os anula.

Coordenação completa da reserva.

Cancelamento e UPDATE em lote

Para libertar capacidade uma vez, condiciona a transição ao bilhete reservado do comprador autenticado:

  1. O UPDATE do bilhete só avança se id, comprador e estado coincidirem; o RETURNING fornece a sessão.
  2. O UPDATE do contador usa esse resultado, na mesma instrução.
  3. Repetir não encontra reservado e não liberta outro lugar; se falhar o contador, anula-se também a transição.

Zero linhas não distingue sozinho ausência, recusa de dono ou estado incompatível.

Com dois triggers AFTER UPDATE, um por linha e outro por instrução:

Linhas encontradasROWSTATEMENT
331
001

SET preco=preco pode disparar ROW sem mudar o valor. IS DISTINCT FROM no corpo permite auditar só mudanças reais; ativação e ação do trigger são decisões diferentes.

Cancelamento atómico e ativações em lote.

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.