Evite Deadlocks: Como Lidar com Concorrência em Banco de Dados
Como Deadlocks Acontecem?
Os principais motivos para a ocorrência de deadlocks incluem:
- Ordem inconsistente de acesso a recursos: Transações acessam recursos em ordens diferentes.
- Transações longas: Mantêm os bloqueios por mais tempo, aumentando as chances de conflitos.
- Uso excessivo de bloqueios exclusivos: Limita a possibilidade de leitura por outras transações.
Como Evitar Deadlocks
1. Acesse Recursos em Ordem Consistente
Defina uma ordem clara de acesso aos recursos e siga essa ordem em todas as transações. Isso reduz significativamente o risco de impasses.
Exemplo: Se você precisa acessar as Tabelas A e B:
- Sempre acesse a Tabela A antes da Tabela B.
2. Mantenha Transações Curtas
Reduza o tempo em que uma transação mantém os bloqueios. Faça apenas o necessário dentro de uma transação e finalize-a rapidamente.
3. Use Bloqueios Apropriadamente
Escolha bloqueios de menor granularidade quando possível (linhas em vez de tabelas inteiras). Considere o uso de bloqueios otimizados, como o SELECT … FOR UPDATE com colunas específicas.
SELECT col1, col2 FROM my_table WHERE id = 123 FOR UPDATE;
Detectando Deadlocks
No Oracle o erro de deadlock pode ser retornado da seguinte forma:
ORA-00060: deadlock detected while waiting for resource
E as tabelas que podem ser consultadas para auxiliar no processo de detecção dos deadlocks no Oracle são: V$LOCK
e V$SESSION
.
Para visualizar/identificar transações e recursos envolvidos a query abaixo poderá ser utilizada:
SELECT session_id, blocking_session, wait_class, event FROM v$session WHERE blocking_session IS NOT NULL;
Na mesma linha de detecção é possível ativar logs de diagnostico para capturar maiores detalhes:
ALTER SYSTEM SET EVENTS '60 trace name context forever, level 10';
Exemplos práticos
-- Operação 1
BEGIN;
UPDATE produtos SET saldo = saldo - 100 WHERE id_produto = 1;
UPDATE produtos SET saldo = saldo + 100 WHERE id_produto = 2;
-- Operação 2
BEGIN;
UPDATE produtos SET saldo = saldo - 100 WHERE id_produto = 2;
UPDATE produtos SET saldo = saldo + 100 WHERE id_produto = 1;
SOLUÇÃO
-- Operação 1
BEGIN;
UPDATE produtos SET saldo = saldo - 100 WHERE id_produto = 1;
UPDATE produtos SET saldo = saldo + 100 WHERE id_produto = 2;
COMMIT;
-- Operação 2
BEGIN;
UPDATE produtos SET saldo = saldo - 100 WHERE id_produto = 1;
UPDATE produtos SET saldo = saldo + 100 WHERE id_produto = 2;
COMMIT;
Conclusão
Neste post tentei de forma prática e resumida demonstrar como identificar e como resolver problemas relacionados ao deadlocks.
Deadlocks são mais do que simples desafios técnicos; eles representam pontos críticos na gestão de concorrência em sistemas de banco de dados. Compreendê-los a fundo e adotar práticas proativas para evitá-los é essencial para garantir a fluidez das operações, a integridade dos dados e a eficiência das aplicações.
Ao implementar estratégias como o acesso consistente a recursos, a redução da duração das transações e o uso criterioso de bloqueios, você estará fortalecendo a base do seu sistema contra impasses. Além disso, monitorar e diagnosticar possíveis conflitos com as ferramentas disponíveis permite corrigir problemas rapidamente e prevenir recorrências.
Enfrentar deadlocks é uma oportunidade para aprimorar o design de transações e elevar o nível de confiabilidade do seu banco de dados. Afinal, evitar esses bloqueios não é apenas uma questão de performance, mas de proporcionar um ambiente robusto e escalável, preparado para suportar as demandas de sistemas críticos.
Referências
Da hora