Transações no PostgreSQL garantem isolamento — uma das paradas chave do ACID. Pra isso, o sistema usa locks. Lock é tipo um mecanismo que garante que várias transações não vão "brigar" pelo mesmo registro ou tabela. Imagina uma fila no mercado: só um de cada vez passa no caixa. Os locks funcionam mais ou menos assim, só que eles controlam o acesso aos dados nas tabelas.
Principais tipos de locks
No PostgreSQL tem vários tipos de locks, alguns deles você talvez já tenha visto no EXPLAIN ANALYZE:
ROW EXCLUSIVE(lock exclusivo de linha) — rola quando você altera dados numa linha. É o tipo de lock mais comum, tipo quando fazINSERT,UPDATEouDELETE.SHARE(lock compartilhado) — usado pra operações que garantem que os dados não vão mudar enquanto a query roda, tipo quando fazSELECT ... FOR SHARE.EXCLUSIVE(lock exclusivo) — bloqueia qualquer outra operação nos dados, menos leitura.
Dá pra dizer que locks são tipo cachorros de guarda protegendo nossos dados.
Problema dos locks: o que pode dar ruim?
Agora que já sacou o que são locks, bora ver os problemas que eles podem causar. O maior deles é o tal do deadlock. Deadlock é quando duas (ou mais) transações ficam esperando uma pela outra, e aí tudo trava num loop infinito. Normalmente rola assim:
- Transação 1 bloqueia a linha A e quer acessar a linha B.
- Transação 2 bloqueia a linha B e quer acessar a linha A.
- Como as duas linhas estão bloqueadas, nenhuma transação consegue terminar.
Exemplo de deadlock
Pra sentir a dor de quem já tomou um deadlock, imagina esse cenário:
-- Transação 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- Ao mesmo tempo
-- Transação 2
BEGIN;
UPDATE accounts SET balance = balance + 200 WHERE id = 2;
-- Transação 1 tenta bloquear id = 2
UPDATE accounts SET balance = balance - 100 WHERE id = 2;
-- Transação 2 tenta bloquear id = 1
UPDATE accounts SET balance = balance + 200 WHERE id = 1;
Pronto! Cada transação ficou presa pela outra. O PostgreSQL uma hora percebe isso e manda um erro de deadlock.
Como evitar deadlocks?
- Ordem sequencial de acesso aos dados. Tenta sempre acessar os dados na mesma ordem. Se a transação 1 primeiro bloqueia a linha A e depois a B, a transação 2 tem que seguir a mesma lógica: primeiro linha A, depois linha B.
-- Ordem certa de acesso
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 200 WHERE id = 2;
COMMIT;
Minimiza o tempo das transações. Transações demoradas aumentam a chance de deadlock. Fecha a transação o mais rápido possível:
BEGIN, faz tudo que precisa e já manda umCOMMIT.Usa níveis de isolamento de transação. Se não precisa de isolamento super rígido, pensa em usar o nível
READ COMMITTED. Ele ajuda a evitar alguns locks.
Timeouts e diagnóstico de locks
Tem umas ferramentas pra diagnosticar e evitar locks no PostgreSQL. Por exemplo, dá pra definir um tempo máximo de espera do lock:
SET lock_timeout = '5s'; -- Define o timeout do lock pra 5 segundos
Se o lock durar mais que esse tempo, a transação é cancelada, evitando que tudo trave geral.
Monitorando locks no PostgreSQL
Um comando útil pra monitorar locks é o pg_locks. Ele mostra todos os locks ativos no sistema:
SELECT * FROM pg_locks;
Dá pra ver quais transações estão segurando locks e quais estão esperando. Isso é top pra debugar deadlocks.
Detalhes do LOCK e lock manual de objetos
Se precisar controlar locks na mão, usa o comando LOCK:
LOCK TABLE orders IN ACCESS EXCLUSIVE MODE;
Atenção: ACCESS EXCLUSIVE é o lock mais forte, bloqueia qualquer operação na tabela, até SELECT. Só usa isso em casos especiais (tipo mudar a estrutura da tabela).
Pra bloquear linhas específicas durante alteração, usa SELECT ... FOR UPDATE:
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
Isso garante que outras transações não vão conseguir mexer nessas linhas até sua transação acabar.
O que lembrar sobre locks?
Lock não é vilão, é ferramenta. Eles ajudam a manter a integridade dos dados, mas tem que usar com cuidado. Aqui vão umas dicas chave:
- Não começa uma transação se não souber exatamente pra quê.
- Fecha a transação o mais rápido possível.
- Evita acessar dados em ordem diferente.
- Usa o nível de isolamento certo pra sua necessidade.
Agora você tá pronto pra lidar com locks e deadlocks! Que o pg_locks e a sabedoria do ACID estejam com você.
GO TO FULL VERSION