Entendo as diferenças entre o bloqueio otimista e o pessimista. Agora alguém poderia me explicar quando eu usaria qualquer um deles em geral?
E a resposta a esta pergunta muda dependendo se estou usando um procedimento armazenado ou não para executar a consulta?
Mas apenas para verificar, otimista significa "não tranque a mesa enquanto lê" e pessimista significa "tranque a mesa durante a leitura".
sql-server
locking
optimistic-locking
pessimistic-locking
Jason Baker
fonte
fonte
At any technique type conflicts should be detected and considered, with similar overhead for both materialized and non-materialized conflicts
.Respostas:
O bloqueio otimista é uma estratégia na qual você lê um registro, anota um número de versão (outros métodos para fazer isso envolvem datas, carimbos de hora ou somas de verificação / hashes) e verifica se a versão não mudou antes de gravar o registro. Ao gravar o registro, você filtra a atualização na versão para garantir que ela seja atômica. (ou seja, não foi atualizado entre quando você verifica a versão e grava o registro no disco) e atualiza a versão em uma ocorrência.
Se o registro estiver sujo (ou seja, versão diferente da sua), você cancelará a transação e o usuário poderá reiniciá-la.
Essa estratégia é mais aplicável a sistemas de alto volume e arquiteturas de três camadas em que você não mantém necessariamente uma conexão com o banco de dados para sua sessão. Nessa situação, o cliente não pode realmente manter bloqueios de banco de dados, pois as conexões são obtidas de um pool e você pode não estar usando a mesma conexão de um acesso para o próximo.
Bloqueio pessimista é quando você bloqueia o registro para seu uso exclusivo até terminar com ele. Tem uma integridade muito melhor do que o bloqueio otimista, mas exige que você tenha cuidado com o design do aplicativo para evitar deadlocks . Para usar o bloqueio pessimista, você precisa de uma conexão direta com o banco de dados (como seria o caso em um aplicativo de servidor cliente de duas camadas ) ou um ID de transação disponível externamente que possa ser usado independentemente da conexão.
No último caso, você abre a transação com o TxID e reconecta usando esse ID. O DBMS mantém os bloqueios e permite que você selecione a sessão novamente através do TxID. É assim que as transações distribuídas usando protocolos de confirmação de duas fases (como transações XA ou COM + ) funcionam.
fonte
O bloqueio otimista é usado quando você não espera muitas colisões. Custa menos realizar uma operação normal, mas se ocorrer uma colisão, você pagaria um preço mais alto para resolvê-lo quando a transação for interrompida.
O bloqueio pessimista é usado quando uma colisão é antecipada. As transações que violariam a sincronização são simplesmente bloqueadas.
Para selecionar o mecanismo de bloqueio adequado, é necessário estimar a quantidade de leituras e gravações e planejar adequadamente.
fonte
Otimista assume que nada vai mudar enquanto você estiver lendo.
Pessimista pressupõe que algo o fará e assim o trava.
Se não for essencial que os dados sejam perfeitamente lidos, use otimista. Você pode ter uma leitura estranha 'suja' - mas é muito menos provável que resulte em impasses e similares.
A maioria dos aplicativos da Web é boa com leituras sujas - nas raras ocasiões em que os dados não são exatamente iguais na próxima recarga.
Para operações exatas de dados (como em muitas transações financeiras), use pessimista. É essencial que os dados sejam lidos com precisão, sem alterações não mostradas - a sobrecarga de bloqueio extra vale a pena.
Ah, e o Microsoft SQL Server assume como padrão o bloqueio de páginas - basicamente a linha que você está lendo e algumas de cada lado. O bloqueio de linhas é mais preciso, mas muito mais lento. Muitas vezes, vale a pena definir suas transações como confirmadas por leitura ou sem bloqueio para evitar conflitos durante a leitura.
fonte
Além do que já foi dito:
optimistic
bloqueio tende a melhorar a simultaneidade à custa da previsibilidade.Pessimistic
o bloqueio tende a reduzir a simultaneidade, mas é mais previsível. Você paga seu dinheiro, etc ...fonte
Ao lidar com conflitos, você tem duas opções:
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 de1
, 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, BobUPDATE
retomará e aplicará a alteração. Até Alice liberar o bloqueio de leitura, o UPDATE de Bob bloqueia.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 . Aversion
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 correnteversion
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.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.
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.
fonte
PESSIMISTIC_FORCE_INCREMENT
.Pensaria em mais um caso em que o bloqueio pessimista seria uma escolha melhor.
Para um bloqueio otimista, todo participante na modificação de dados deve concordar em usar esse tipo de bloqueio. Mas se alguém modificar os dados sem se preocupar com a coluna da versão, isso estragará toda a idéia do bloqueio otimista.
fonte
Existem basicamente duas respostas mais populares. O primeiro diz basicamente
Outra resposta é
ou
Como está colocado nesta página.
Eu criei minha resposta para explicar como "manter conexão" está relacionado a "baixas colisões".
Para entender qual estratégia é melhor para você, pense não nas transações por segundo que seu banco de dados possui, mas na duração de uma única transação. Normalmente, você abre a transação, realiza a operação e fecha a transação. Essa é uma transação clássica clássica, curta, que a ANSI tinha em mente e muito bem para se livrar do bloqueio. Mas como você implementa um sistema de reserva de bilhetes em que muitos clientes reservam os mesmos quartos / assentos ao mesmo tempo?
Você navega nas ofertas, preenche o formulário com muitas opções disponíveis e preços atuais. Demora muito tempo e as opções podem se tornar obsoletas, todos os preços inválidos entre você começaram a preencher o formulário e pressione o botão "Eu concordo" porque não havia bloqueio nos dados que você acessou e que outra pessoa, mais ágil, interferiu alterando todos os preços e você precisa reiniciar com novos preços.
Você pode bloquear todas as opções enquanto as lê. Este é um cenário pessimista. Você vê por que é uma porcaria. Seu sistema pode ser derrubado por um único palhaço que simplesmente inicia uma reserva e vai fumar. Ninguém pode reservar nada antes que ele termine. Seu fluxo de caixa cai para zero. É por isso que reservas otimistas são usadas na realidade. Aqueles que demoram demais precisam reiniciar sua reserva a preços mais altos.
Nessa abordagem otimista, você deve registrar todos os dados que lê (como na minha Leitura repetida ) e chegar ao ponto de confirmação com sua versão dos dados (desejo comprar ações pelo preço que você indicou nesta cotação, não pelo preço atual ) Nesse ponto, a transação ANSI é criada, o que bloqueia o banco de dados, verifica se nada foi alterado e confirma / interrompe sua operação. Na IMO, essa é uma emulação efetiva do MVCC , que também está associada ao Optimistic CC e também pressupõe que sua transação seja reiniciada em caso de abortamento, ou seja, você fará uma nova reserva. Uma transação aqui envolve decisões de um usuário humano.
Estou longe de entender como implementar o MVCC manualmente, mas acho que transações de longa duração com opção de reinicialização são a chave para entender o assunto. Corrija-me se estiver errado em algum lugar. Minha resposta foi motivada por este capítulo de Alex Kuznecov .
fonte
Na maioria dos casos, o bloqueio otimista é mais eficiente e oferece maior desempenho. Ao escolher entre bloqueio pessimista e otimista, considere o seguinte:
O bloqueio pessimista é útil se houver muitas atualizações e chances relativamente altas de os usuários tentarem atualizar os dados ao mesmo tempo. Por exemplo, se cada operação puder atualizar um grande número de registros por vez (o banco pode adicionar juros a todas as contas no final de cada mês) e dois aplicativos estiverem executando essas operações ao mesmo tempo, eles terão conflitos .
O bloqueio pessimista também é mais apropriado em aplicativos que contêm pequenas tabelas que são atualizadas frequentemente. No caso desses chamados pontos de acesso, os conflitos são tão prováveis que o bloqueio otimista desperdiça esforços para reverter transações conflitantes.
O bloqueio otimista é útil se a possibilidade de conflitos for muito baixa - existem muitos registros, mas relativamente poucos usuários, ou muito poucas atualizações e, principalmente, operações do tipo leitura.
fonte
Um caso de uso para bloqueio otimista é fazer com que seu aplicativo use o banco de dados para permitir que um de seus threads / hosts 'reivindique' uma tarefa. Essa é uma técnica que é útil para mim regularmente.
O melhor exemplo em que posso pensar é em uma fila de tarefas implementada usando um banco de dados, com vários threads reivindicando tarefas simultaneamente. Se uma tarefa tiver o status 'Disponível', 'Reivindicado', 'Concluído', uma consulta db poderá dizer algo como "Definir status = 'Reivindicado' em que status = 'Disponível'. Se vários encadeamentos tentarem alterar o status dessa maneira, todos, exceto o primeiro encadeamento, falharão devido a dados sujos.
Observe que este é um caso de uso que envolve apenas bloqueio otimista. Portanto, como alternativa a dizer "O bloqueio otimista é usado quando você não espera muitas colisões", também pode ser usado onde você espera colisões, mas deseja que exatamente uma transação seja bem-sucedida.
fonte
Muitas coisas boas foram ditas acima sobre travas otimistas e pessimistas. Um ponto importante a considerar é o seguinte:
Ao usar o bloqueio otimista, precisamos ter cuidado com o fato de como o aplicativo se recuperará dessas falhas.
Especialmente em arquiteturas assíncronas orientadas a mensagens, isso pode levar ao processamento de mensagens fora de ordem ou a atualizações perdidas.
Cenários de falhas precisam ser pensados.
fonte