PostgreSQL: Transações e Controle de Concorrência no…

Última atualização: 2026-08-26

1. O Que Você Vai Aprender


2. A História

Alice é responsável pelo sistema de pedidos de uma plataforma de e-commerce. Durante uma promoção, um item de edição limitada tinha apenas 1 unidade restante em estoque, e dois usuários fizeram pedidos quase simultaneamente:

Sem proteção de transação, ambos poderiam fazer pedidos com sucesso, levando o estoque a -1 e causando venda excessiva. Alice precisa dos mecanismos de isolamento de transação, MVCC e bloqueio de linha do PostgreSQL para garantir que apenas um usuário deduza o estoque com sucesso enquanto o outro é bloqueado ou recebe um erro—garantindo a consistência dos dados.


3. Conceito: ACID e Fundamentos de Transações

(1) As Quatro Propriedades ACID

Propriedade Inglês Significado Implementação no PostgreSQL
Atomicidade Atomicity Uma transação é tudo ou nada: sucesso total ou rollback total WAL (Write-Ahead Log)
Consistência Consistency O banco de dados satisfaz suas restrições antes e depois de uma transação Restrições, triggers, verificações de tipo
Isolamento Isolation Transações concorrentes não interferem umas nas outras MVCC + bloqueios
Durabilidade Durability Dados commitados não são perdidos WAL + fsync

▶ Exemplo: Atomicidade ACID—Transferência ou Tem Sucesso Total ou Rollback Total

SQL
BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 500 WHERE account_id = 2;
COMMIT;

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso

(2) Instruções de Controle de Transação

Instrução Finalidade SQL correspondente
Iniciar transação Abrir explicitamente uma transação BEGIN ou START TRANSACTION
Confirmar transação Persistir todas as alterações COMMIT
Reverter transação Desfazer todas as alterações ROLLBACK

▶ Exemplo: Reverter uma Transaç��o para Restaurar Dados

SQL
BEGIN;
DELETE FROM orders WHERE order_id = 999;
-- Ops, exclusão errada!
ROLLBACK;
-- Os dados são restaurados

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso

(3) Modo Autocommit

O PostgreSQL habilita Autocommit por padrão—cada instrução SQL é automaticamente commitada como sua própria transação.

Modo Comportamento Configuração no psql
Autocommit ON Cada instrução faz auto-commit Padrão
Autocommit OFF COMMIT manual necessário \set AUTOCOMMIT off

▶ Exemplo: Desabilitar Autocommit e Fazer Commit Manualmente

BASH
\set AUTOCOMMIT off
DELETE FROM orders WHERE order_status = 'cancelled';
-- Verificar antes de commitar
SELECT count(*) FROM orders WHERE order_status = 'cancelled';
COMMIT;

Output:

TEXT 📖 Somente leitura
# comando executado com sucesso

(4) Rollback Parcial com SAVEPOINT

Defina um savepoint dentro de uma transação para poder reverter apenas até esse savepoint, em vez de toda a transação.

▶ Exemplo: Usar SAVEPOINT para Rollback Parcial

SQL
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
SAVEPOINT sp1;
UPDATE accounts SET balance = balance - 200 WHERE account_id = 1;
-- A segunda atualização estava errada, reverter para o savepoint
ROLLBACK TO SAVEPOINT sp1;
-- A primeira atualização ainda está ativa, pode commitar
COMMIT;

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso
Instrução Finalidade
SAVEPOINT sp_nome Criar um savepoint
ROLLBACK TO SAVEPOINT sp_nome Reverter para um savepoint
RELEASE SAVEPOINT sp_nome Liberar um savepoint (rollbacks posteriores não podem referenciá-lo)

4. Conceito: Níveis de Isolamento de Transação

(1) Os Três Níveis de Isolamento do PostgreSQL

O PostgreSQL implementa apenas três níveis de isolamento (READ UNCOMMITTED é mapeado para READ COMMITTED):

Nível de isolamento Leitura suja Leitura não repetível Leitura fantasma Implementação no PG
READ COMMITTED Impossível Possível Possível Nível padrão; cada consulta vê o último snapshot commitado
REPEATABLE READ Impossível Impossível Possível (PG realmente previne fantasmas) A transação vê o snapshot do seu início
SERIALIZABLE Impossível Impossível Impossível Mais rigoroso; detecta conflitos de serialização

▶ Exemplo: Definir o Nível de Isolamento

SQL
BEGIN ISOLATION LEVEL READ COMMITTED;
-- ou
BEGIN ISOLATION LEVEL REPEATABLE READ;
-- ou
BEGIN ISOLATION LEVEL SERIALIZABLE;

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso

(2) READ COMMITTED vs REPEATABLE READ na Prática

▶ Exemplo: READ COMMITTED—Duas Consultas na Mesma Transação Retornam Resultados Diferentes

SQL
-- Sessão 1
BEGIN ISOLATION LEVEL READ COMMITTED;
SELECT balance FROM accounts WHERE account_id = 1; -- Retorna 1000

-- Sessão 2 (outra conexão)
UPDATE accounts SET balance = 800 WHERE account_id = 1;
COMMIT;

-- De volta à Sessão 1
SELECT balance FROM accounts WHERE account_id = 1; -- Retorna 800 (vê alteração commitada)
COMMIT;

Output:

TEXT 📖 Somente leitura
 count 
-------
     5
(1 row)

▶ Exemplo: REPEATABLE READ—Duas Consultas na Mesma Transação Retornam Resultados Consistentes

SQL
-- Sessão 1
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT balance FROM accounts WHERE account_id = 1; -- Retorna 1000

-- Sessão 2 (outra conexão)
UPDATE accounts SET balance = 800 WHERE account_id = 1;
COMMIT;

-- De volta à Sessão 1
SELECT balance FROM accounts WHERE account_id = 1; -- Ainda retorna 1000
COMMIT;

Output:

TEXT 📖 Somente leitura
 count 
-------
     5
(1 row)

(3) Nível de Isolamento SERIALIZABLE

SERIALIZABLE é o nível mais rigoroso; o PostgreSQL usa Serializable Snapshot Isolation (SSI) para detectar conflitos de serialização.

▶ Exemplo: Detecção de Conflito no SERIALIZABLE

SQL
-- Sessão 1
BEGIN ISOLATION LEVEL SERIALIZABLE;
SELECT balance FROM accounts WHERE account_id = 1;

-- Sessão 2
BEGIN ISOLATION LEVEL SERIALIZABLE;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;

-- De volta à Sessão 1
UPDATE accounts SET balance = balance + 50 WHERE account_id = 1;
-- ERRO: não foi possível serializar o acesso devido a atualização concorrente

Output:

TEXT 📖 Somente leitura
 count 
-------
     5
(1 row)
Escolha do nível de isolamento Cenário Nível recomendado
Maioria das apps web READ COMMITTED Padrão, equilibra desempenho e consistência
Relatórios/auditorias que precisam de snapshot consistente REPEATABLE READ Leituras na mesma transação permanecem consistentes
Transações bancárias/financeiras centrais SERIALIZABLE Mais rigoroso, troca desempenho por segurança

5. Conceito: MVCC - Controle de Concorrência Multiversão

(1) Princípio Central do MVCC

MVCC (Multi-Version Concurrency Control) é o núcleo do controle de concorrência do PostgreSQL. Cada transação vê um snapshot dos dados em um ponto no tempo; leituras não bloqueiam escritas, e escritas não bloqueiam leituras.

Cada versão de linha (tupla) contém quatro campos ocultos:

Campo Significado
xmin O ID da transação que inseriu a linha
xmax O ID da transação que excluiu/atualizou a linha (0 significa ainda válida)
Visibilidade xmin Uma transação cujo ID < snapshot atual pode ver esta linha
Visibilidade xmax Uma transação cujo ID >= snapshot atual não pode ver esta exclusão

▶ Exemplo: Visualizar Informações de Versão de uma Linha

SQL
SELECT xmin, xmax, * FROM products WHERE product_id = 1;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(2) Fluxo de Concorrência de Leitura/Escrita no MVCC

100%
sequenceDiagram
    participant R as Leitor(Tx1)
    participant W as Escritor(Tx2)
    participant T as Tabela

    R->>T: SELECT (snapshot no início de Tx1)
    T-->>R: Retorna versão V1 (xmin=100, xmax=0)
    W->>T: UPDATE (cria nova versão)
    T-->>T: V1 xmax=200, V2 xmin=200 xmax=0
    R->>T: SELECT novamente (mesmo snapshot)
    T-->>R: Ainda retorna V1 (Tx2 não commitou)
    W->>T: COMMIT
    Note over T: V2 agora visível para novas transações
    R->>T: SELECT novamente (mesmo snapshot)
    T-->>R: Ainda retorna V1 (REPEATABLE READ)

▶ Exemplo: Leituras MVCC Não Bloqueiam Escritas

SQL
-- Sessão 1: Leitura de longa duração
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT * FROM orders WHERE order_date = '2025-01-01';
-- Esta consulta NÃO bloqueia escritores

-- Sessão 2: Escrita concorrente (sem bloqueio da Sessão 1)
UPDATE orders SET order_status = 'shipped' WHERE order_id = 100;
COMMIT;

Output:

TEXT 📖 Somente leitura
UPDATE 3

(3) O Custo do MVCC: Tuplas Mortas e VACUUM

Um UPDATE no MVCC não modifica a linha original—cria uma nova versão. A linha antiga se torna uma tupla morta e precisa de limpeza VACUUM.

Operação Comportamento MVCC Tuplas mortas
INSERT Cria uma nova linha Nenhuma
DELETE Marca o xmax da linha antiga Produz 1 tupla morta
UPDATE Marca o xmax da linha antiga + cria nova linha Produz 1 tupla morta

▶ Exemplo: Visualizar Contagem de Tuplas Mortas

SQL
SELECT relname, n_live_tup, n_dead_tup, last_vacuum, last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ Exemplo: Disparar VACUUM Manualmente

SQL
VACUUM orders;              -- Recupera espaço, não bloqueia leituras
VACUUM FULL orders;         -- Reescrita completa da tabela, bloqueia a tabela
VACUUM ANALYZE orders;      -- Recupera + atualiza estatísticas

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso
Tipo de VACUUM Nível de bloqueio Recupera espaço Velocidade
VACUUM SHARE Marca como reutilizável, não devolve ao disco Rápido
VACUUM FULL ACCESS EXCLUSIVE Devolve totalmente ao disco Lento, bloqueia tabela
VACUUM ANALYZE SHARE Igual ao VACUUM + atualiza estatísticas Rápido

6. Conceito: Bloqueios

(1) Bloqueios de Linha

O PostgreSQL adquire automaticamente um bloqueio de linha ao modificar uma linha; outras transações devem esperar.

Tipo de bloqueio de linha Como adquirir Conflito
FOR UPDATE SELECT ... FOR UPDATE Bloqueio exclusivo, bloqueia outros FOR UPDATE / FOR NO KEY UPDATE
FOR NO KEY UPDATE SELECT ... FOR NO KEY UPDATE Não bloqueia FOR KEY SHARE
FOR SHARE SELECT ... FOR SHARE Bloqueia FOR UPDATE / FOR NO KEY UPDATE
FOR KEY SHARE SELECT ... FOR KEY SHARE Mais fraco, bloqueia apenas FOR UPDATE

▶ Exemplo: SELECT FOR UPDATE Previne Venda Excessiva

SQL
BEGIN;
SELECT stock FROM products WHERE product_id = 1 FOR UPDATE;
-- stock = 1, linha bloqueada
UPDATE products SET stock = stock - 1 WHERE product_id = 1;
COMMIT;
-- Se outra transação tentar FOR UPDATE na mesma linha, ela espera

Output:

TEXT 📖 Somente leitura
UPDATE 3

(2) Bloqueios de Tabela

Modo de bloqueio Como adquirir Conflito
ACCESS SHARE SELECT Conflita com ACCESS EXCLUSIVE
ROW SHARE SELECT FOR Conflita com EXCLUSIVE / ACCESS EXCLUSIVE
ROW EXCLUSIVE UPDATE/DELETE Conflita com SHARE / EXCLUSIVE, etc.
SHARE LOCK TABLE ... SHARE Conflita com ROW EXCLUSIVE, etc.
ACCESS EXCLUSIVE ALTER TABLE Conflita com todos os bloqueios

▶ Exemplo: Bloqueio Explícito de Tabela

SQL
LOCK TABLE orders IN ACCESS EXCLUSIVE MODE;
-- Realizar operações críticas
COMMIT;

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso

(3) Bloqueios Consultivos (Específicos do PostgreSQL)

Bloqueios Consultivos são bloqueios no nível da aplicação, não vinculados a nenhuma linha de tabela, adequados para coordenação distribuída.

Função Característica
pg_try_advisory_lock(id) Não bloqueante; retorna false imediatamente em caso de falha
pg_advisory_lock(id) Bloqueia esperando até adquirir
pg_advisory_unlock(id) Libera o bloqueio
pg_advisory_xact_lock(id) Liberado automaticamente no fim da transação

▶ Exemplo: Usar Bloqueio Consultivo para Prevenir Processamento Duplicado

SQL
-- Tentativa não bloqueante
SELECT pg_try_advisory_lock(12345);
-- Retorna true: obteve o bloqueio, prosseguir
-- Retorna false: outra sessão o mantém, pular

-- Bloqueio consultivo no nível da transação (liberação automática no COMMIT/ROLLBACK)
BEGIN;
SELECT pg_advisory_xact_lock(12345);
-- Fazer o trabalho...
COMMIT; -- Bloqueio liberado automaticamente

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ Exemplo: Bloqueio Consultivo para Tarefas de Instância Única

SQL
CREATE FUNCTION run_daily_report() RETURNS void AS $$
BEGIN
  IF pg_try_advisory_lock(99999) THEN
    -- Apenas uma sessão pode executar isso por vez
    INSERT INTO report_log (report_date, status)
    VALUES (CURRENT_DATE, 'running');
    PERFORM pg_sleep(5); -- Simular trabalho
    UPDATE report_log SET status = 'done' WHERE report_date = CURRENT_DATE;
    PERFORM pg_advisory_unlock(99999);
  ELSE
    RAISE NOTICE 'Relatório já em execução em outra sessão';
  END IF;
END;
$$ LANGUAGE plpgsql;

Output:

TEXT 📖 Somente leitura
INSERT 0 1

7. Conceito: Detecção e Tratamento de Deadlock

(1) Como os Deadlocks Surgem

Duas transações esperam pelos bloqueios mantidos uma pela outra, formando uma dependência circular.

100%
flowchart LR
    A[Tx1: Bloquear Linha A] -->|Esperar pela Linha B| B[Tx2: Bloquear Linha B]
    B -->|Esperar pela Linha A| A
    A -->|Deadlock!| C[PG detecta automaticamente em 1s]

▶ Exemplo: Cenário de Deadlock

SQL
-- Sessão 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1; -- Bloquear linha 1

-- Sessão 2
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 2; -- Bloquear linha 2

-- Sessão 1 (agora espera pela linha 2)
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;

-- Sessão 2 (deadlock!)
UPDATE accounts SET balance = balance + 100 WHERE account_id = 1;
-- ERRO: deadlock detectado

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso

(2) Detecção e Prevenção de Deadlock

Estratégia Descrição
Detecção automática O PostgreSQL verifica uma vez por segundo por padrão (deadlock_timeout)
Rollback automático Ao detectar um deadlock, reverte automaticamente uma transação
Ordem fixa de bloqueio Sempre adquira bloqueios na mesma ordem, evitando esperas circulares
Transações curtas Reduza o tempo que uma transação mantém bloqueios

▶ Exemplo: Prevenir Deadlocks com Ordem Fixa de Bloqueio

SQL
-- Sempre bloquear linhas em ordem de account_id
BEGIN;
SELECT * FROM accounts WHERE account_id IN (1, 2) ORDER BY account_id FOR UPDATE;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT;

Output:

TEXT 📖 Somente leitura
 count 
-------
     5
(1 row)

8. Conceito: Bloqueio Pessimista vs Bloqueio Otimista

(1) Comparando as Duas Estratégias de Concorrência

Dimensão Bloqueio pessimista Bloqueio otimista
Ideia Bloquear primeiro, depois modificar; bloquear em conflito Modificar primeiro, depois verificar; tentar novamente em conflito
Implementação SELECT FOR UPDATE coluna version + WHERE version = antiga
Frequência de conflito Adequado para cenários de alto conflito Adequado para cenários de baixo conflito
Desempenho Sobrecarga de espera de bloqueio Sobrecarga de nova tentativa
Risco de deadlock Sim Não

▶ Exemplo: Bloqueio Pessimista para Dedução de Estoque

SQL
BEGIN;
SELECT stock FROM products WHERE product_id = 1 FOR UPDATE;
-- stock = 1, linha bloqueada
IF stock > 0 THEN
  UPDATE products SET stock = stock - 1 WHERE product_id = 1;
END IF;
COMMIT;

Output:

TEXT 📖 Somente leitura
UPDATE 3

▶ Exemplo: Bloqueio Otimista para Dedução de Estoque

SQL
-- Adicionar coluna version
ALTER TABLE products ADD COLUMN version INT DEFAULT 1;

-- Atualização otimista
UPDATE products
SET stock = stock - 1, version = version + 1
WHERE product_id = 1 AND version = 5;
-- Se linhas afetadas = 0, alguém modificou, precisa tentar novamente

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso

▶ Exemplo: Lógica de Nova Tentativa no Bloqueio Otimista na Camada de Aplicação

SQL
CREATE FUNCTION deduct_stock(p_id INT, p_qty INT) RETURNS BOOLEAN AS $$
DECLARE
  v_version INT;
  v_stock INT;
  v_updated INT;
BEGIN
  LOOP
    SELECT stock, version INTO v_stock, v_version
    FROM products WHERE product_id = p_id;

    IF v_stock < p_qty THEN RETURN FALSE; END IF;

    UPDATE products
    SET stock = stock - p_qty, version = version + 1
    WHERE product_id = p_id AND version = v_version;

    GET DIAGNOSTICS v_updated = ROW_COUNT;
    IF v_updated > 0 THEN RETURN TRUE; END IF;
    -- Conflito, tentar novamente
  END LOOP;
END;
$$ LANGUAGE plpgsql;

Output:

TEXT 📖 Somente leitura
 count 
-------
     5
(1 row)

9. Conceito: Commit em Duas Fases (2PC)

(1) 2PC para Transações Distribuídas

Quando uma transação abrange múltiplos bancos de dados ou recursos externos, o commit em duas fases é necessário para garantir a atomicidade.

Fase Operação Descrição
PREPARE PREPARE TRANSACTION 'tx_id' A transação entra em estado preparado, gravada no WAL
COMMIT COMMIT PREPARED 'tx_id' A Fase 2 confirma o commit
ROLLBACK ROLLBACK PREPARED 'tx_id' A Fase 2 confirma o rollback

▶ Exemplo: Fluxo de Commit em Duas Fases

SQL
-- Fase 1: Preparar
BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE account_id = 1;
PREPARE TRANSACTION 'transfer_out';

-- (Coordenador confirma que todos os participantes estão preparados)

-- Fase 2: Commit
COMMIT PREPARED 'transfer_out';

Output:

TEXT 📖 Somente leitura
-- instrução SQL executada com sucesso

▶ Exemplo: Visualizar Transações Preparadas

SQL
SELECT * FROM pg_prepared_xacts;

Output:

TEXT 📖 Somente leitura
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)
Parâmetro Padrão Descrição
max_prepared_transactions 0 Deve ser > 0 para usar 2PC
deadlock_timeout 1s Intervalo de detecção de deadlock
idle_in_transaction_session_timeout 0 Tempo limite de inatividade da transação (milissegundos)

10. Na Prática: Transação Completa de Dedução de Estoque para E-Commerce

Alice precisa de uma transação completa de dedução de estoque que lide com pedidos concorrentes, previna venda excessiva e registre o pedido.

SQL
-- Passo 1: Criar tabelas
CREATE TABLE products (
  product_id INT PRIMARY KEY,
  product_name TEXT NOT NULL,
  stock INT NOT NULL DEFAULT 0,
  price NUMERIC(10,2) NOT NULL,
  version INT NOT NULL DEFAULT 1
);

CREATE TABLE orders (
  order_id SERIAL PRIMARY KEY,
  customer_id INT NOT NULL,
  product_id INT NOT NULL,
  quantity INT NOT NULL,
  total_price NUMERIC(10,2) NOT NULL,
  order_status TEXT DEFAULT 'pending',
  created_at TIMESTAMP DEFAULT now()
);

INSERT INTO products VALUES
  (1, 'Limited Edition Watch', 1, 299.99, 1),
  (2, 'Wireless Headphones', 50, 89.99, 1);

-- Passo 2: Abordagem de bloqueio pessimista para itens populares
CREATE FUNCTION place_order(
  p_customer_id INT, p_product_id INT, p_qty INT
) RETURNS INT AS $$
DECLARE
  v_stock INT;
  v_order_id INT;
BEGIN
  BEGIN
    -- Bloquear a linha do produto
    SELECT stock INTO v_stock
    FROM products
    WHERE product_id = p_product_id
    FOR UPDATE;

    IF v_stock < p_qty THEN
      RAISE EXCEPTION 'Estoque insuficiente: % < %', v_stock, p_qty;
    END IF;

    -- Deduzir estoque
    UPDATE products
    SET stock = stock - p_qty
    WHERE product_id = p_product_id;

    -- Criar pedido
    INSERT INTO orders (customer_id, product_id, quantity, total_price)
    VALUES (p_customer_id, p_product_id, p_qty,
            p_qty * (SELECT price FROM products WHERE product_id = p_product_id))
    RETURNING order_id INTO v_order_id;

    RETURN v_order_id;
  EXCEPTION
    WHEN OTHERS THEN
      RAISE NOTICE '%', SQLERRM;
      RETURN -1;
  END;
END;
$$ LANGUAGE plpgsql;

-- Passo 3: Testar pedidos concorrentes
SELECT place_order(101, 1, 1); -- Sucesso, pedido criado
SELECT place_order(102, 1, 1); -- Falha, estoque insuficiente

-- Passo 4: Verificar resultados
SELECT product_id, stock FROM products WHERE product_id = 1;
SELECT order_id, customer_id, order_status FROM orders;

❓ Perguntas Frequentes

P: Por que o PostgreSQL não tem um nível de isolamento READ UNCOMMITTED? R: O PostgreSQL mapeia READ UNCOMMITTED para READ COMMITTED, porque sob a arquitetura MVCC é impossível ler dados não commitados (sempre lê um snapshot), então leituras sujas não podem acontecer no PG.

P: REPEATABLE READ pode prevenir leituras fantasmas? R: O REPEATABLE READ do PostgreSQL realmente pode prevenir leituras fantasmas, indo além do que o padrão SQL exige desse nível. No padrão, apenas SERIALIZABLE previne fantasmas, mas o mecanismo de snapshot MVCC do PG também bloqueia fantasmas sob REPEATABLE READ.

P: SAVEPOINTs podem ser aninhados? R: Sim. SAVEPOINTs suportam aninhamento; um ROLLBACK TO SAVEPOINT interno reverte apenas até aquele savepoint, não afetando os externos. RELEASE SAVEPOINT libera o savepoint nomeado e todos os savepoints criados depois dele.

P: Qual a diferença entre SELECT FOR UPDATE e um UPDATE direto? R: SELECT FOR UPDATE bloqueia a linha primeiro e depois decide se modifica—ideal para operações compostas de "ler e depois escrever"; um UPDATE direto faz tudo em um passo. A vantagem do SELECT FOR UPDATE é que você pode fazer um julgamento de negócio antes de modificar.

P: Quando devo usar VACUUM FULL? R: Apenas quando uma tabela está muito inchada e o VACUUM de rotina não consegue recuperar espaço. VACUUM FULL precisa de um bloqueio ACCESS EXCLUSIVE, durante o qual a tabela fica completamente indisponível. A manutenção de rotina deve depender do autovacuum.

P: Qual a diferença entre um Bloqueio Consultivo e um bloqueio comum? R: Um Bloqueio Consultivo é definido pela aplicação, não vinculado a uma tabela ou linha, e não é liberado automaticamente no fim da transação (a menos que você use a versão xact). Bloqueios comuns são gerenciados automaticamente pelo PostgreSQL e vinculados a objetos específicos do banco de dados.

P: Quando o 2PC é usado? R: 2PC é usado principalmente para transações distribuídas entre bancos de dados ou sistemas, exigindo um coordenador para commit uniforme. Uma transação de banco único usa BEGIN/COMMIT simples; 2PC tem sobrecarga extra e requer configurar max_prepared_transactions.


📖 Resumo


📝 Exercícios

  1. ⭐ Escreva uma transação que transfira 200 USD da conta 1 para a conta 2 na tabela accounts, e faça rollback se a conta 1 tiver saldo insuficiente.

  2. ⭐⭐ Use SAVEPOINT para escrever uma transação: primeiro insira um registro de pedido, depois tente atualizar o estoque; se o estoque for insuficiente, faça rollback para o savepoint mas mantenha o pedido (marque seu status como 'failed'), depois faça commit da transação.

  3. ⭐⭐⭐ Implemente uma versão de bloqueio otimista de dedução de estoque: use uma coluna version, tente novamente automaticamente em conflito concorrente até 3 vezes, e retorne FALSE se todas as 3 falharem. Registre também cada nova tentativa em uma tabela retry_log.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%