Ao lidar com conflitos, você tem duas opções:
- Você pode tentar evitar o conflito, e é isso que o bloqueio pessimista faz.
- Ou você pode permitir que o conflito ocorra, mas é necessário detectá-lo ao confirmar suas transações, e é isso que o Bloqueio Otimista faz.
Agora, vamos considerar a seguinte anomalia de atualização perdida :
A anomalia de atualização perdida pode ocorrer no nível de isolamento Read Committed .
No diagrama acima, podemos ver que Alice acredita que pode retirar 40 dela, account
mas não percebe que Bob acabou de alterar o saldo da conta e agora restam apenas 20 nessa conta.
Bloqueio pessimista
O bloqueio pessimista atinge esse objetivo usando um bloqueio compartilhado ou de leitura na conta, para que Bob seja impedido de alterar a conta.
No diagrama acima, Alice e Bob adquirem um bloqueio de leitura na account
linha da tabela que ambos os usuários leram. O banco de dados adquire esses bloqueios no SQL Server ao usar Leitura Repetível ou Serializável.
Como Alice e Bob leram o account
valor PK de 1
, nenhum deles pode alterá-lo até que um usuário libere o bloqueio de leitura. Isso ocorre porque uma operação de gravação requer uma aquisição de bloqueio de gravação / exclusivo, e bloqueios compartilhados / lidos impedem bloqueios de gravação / exclusivos.
Somente após Alice confirmar sua transação e o bloqueio de leitura ser liberado na account
linha, Bob UPDATE
retomará e aplicará a alteração. Até Alice liberar o bloqueio de leitura, o UPDATE de Bob bloqueia.
Para obter mais detalhes sobre como as estruturas de acesso a dados usam o suporte de bloqueio pessimista do banco de dados subjacente, consulte este artigo .
Bloqueio otimista
O bloqueio otimista permite que o conflito ocorra, mas o detecta ao aplicar o UPDATE de Alice conforme a versão foi alterada.
Desta vez, temos uma version
coluna adicional . A version
coluna é incrementada toda vez que um UPDATE ou DELETE é executado e também é usado na cláusula WHERE das instruções UPDATE e DELETE. Para que isso funcione, precisamos emitir o SELECT e ler a corrente version
antes de executar o UPDATE ou DELETE, caso contrário, não saberíamos qual valor de versão passar para a cláusula WHERE ou incrementar.
Para obter mais detalhes sobre como as estruturas de acesso a dados implementam o bloqueio otimista, consulte este artigo .
Transações no nível do aplicativo
Os sistemas de banco de dados relacional surgiram no final dos anos 70 e início dos anos 80, quando um cliente normalmente se conectava a um mainframe por meio de um terminal. É por isso que ainda vemos os sistemas de banco de dados definirem termos como a configuração SESSION.
Atualmente, pela Internet, não executamos mais leituras e gravações no contexto da mesma transação de banco de dados, e o ACID não é mais suficiente.
Por exemplo, considere o seguinte caso de uso:
Sem o bloqueio otimista, não há como esta Atualização Perdida ter sido capturada, mesmo que as transações do banco de dados usassem Serializable. Isso ocorre porque as leituras e gravações são executadas em solicitações HTTP separadas, portanto, em diferentes transações do banco de dados.
Portanto, o bloqueio otimista pode ajudá-lo a evitar atualizações perdidas, mesmo ao usar transações no nível do aplicativo que incorporam o tempo de reflexão do usuário.
Para obter mais detalhes sobre transações lógicas ou no nível do aplicativo, consulte este artigo .
Conclusão
O bloqueio otimista é uma técnica muito útil e funciona bem mesmo quando se usa níveis de isolamento menos rigorosos, como Read Committed, ou quando leituras e gravações são executadas em transações subsequentes do banco de dados.
A desvantagem do bloqueio otimista é que uma reversão será acionada pela estrutura de acesso a dados ao capturar um OptimisticLockException
, perdendo, portanto, todo o trabalho que fizemos anteriormente pela transação atualmente em execução.
Quanto mais contenção, mais conflitos e maior a chance de abortar transações. As reversões podem ser caras para o sistema de banco de dados, pois ele precisa reverter todas as alterações pendentes atuais, que podem envolver linhas de tabela e registros de índice.
Por esse motivo, o bloqueio pessimista pode ser adequado quando ocorrem conflitos com frequência, pois reduz a chance de reverter transações.