Considere um site de comércio eletrônico, onde Alice e Bob estão editando as listagens de produtos. Alice está melhorando as descrições, enquanto Bob está atualizando os preços. Eles começam a editar o Acme Wonder Widget ao mesmo tempo. Bob termina primeiro e salva o produto com o novo preço. Alice demora um pouco mais para atualizar a descrição e, quando termina, ela salva o produto com sua nova descrição. Infelizmente, ela também substitui o preço pelo preço antigo, que não era o pretendido.
Na minha experiência, esses problemas são extremamente comuns em aplicativos da web. Alguns softwares (por exemplo, software wiki) têm proteção contra isso - geralmente o segundo salvamento falha com "a página foi atualizada enquanto você estava editando". Mas a maioria dos sites não tem essa proteção.
Vale a pena notar que os métodos do controlador são seguros por thread. Geralmente eles usam transações de banco de dados, o que as torna seguras no sentido de que, se Alice e Bob tentarem salvar exatamente no mesmo momento, isso não causará corrupção. A condição de corrida surge de Alice ou Bob terem dados obsoletos em seu navegador.
Como podemos evitar essas condições de corrida? Em particular, eu gostaria de saber:
- Quais técnicas podem ser usadas? por exemplo, rastreando a hora da última alteração. Quais são os prós e contras de cada um.
- O que é uma experiência útil para o usuário?
- Em quais estruturas essa proteção foi incorporada?
fonte
Respostas:
Você precisa "ler suas gravações", o que significa que, antes de anotar uma alteração, é necessário ler o registro novamente e verificar se alguma alteração foi feita desde a última vez que você o leu. Você pode fazer isso campo a campo (granulação fina) ou com base em um carimbo de data / hora (granulação grossa). Enquanto você faz essa verificação, precisa de um bloqueio exclusivo no registro. Se nenhuma alteração foi feita, você pode anotá-las e liberar o bloqueio. Se o registro tiver sido alterado, você interrompe a transação, libera a trava e notifica o usuário.
fonte
Eu vi duas maneiras principais:
Adicione o carimbo de data e hora da última atualização da página que o uso está editando em uma entrada oculta. Ao confirmar o carimbo de data e hora, é verificado o atual e, se não corresponderem, foi atualizado por outra pessoa e retorna um erro.
pro: vários usuários podem editar partes diferentes da página. A página de erro pode levar a uma página de diferenças, na qual o segundo usuário pode mesclar suas alterações na nova página.
con: às vezes, grandes partes do esforço são desperdiçadas durante grandes edições simultâneas.
Quando um usuário começa a editar a página, bloqueie-a por um período de tempo razoável; quando outro usuário tenta editar, ele recebe uma página de erro e precisa esperar até que o bloqueio expire ou o primeiro usuário seja confirmado.
pro: os esforços de edição não são desperdiçados.
con: um usuário sem escrúpulos pode bloquear uma página indefinidamente. Uma página com um bloqueio expirado ainda poderá confirmar, a menos que seja tratado de outra forma (usando a técnica 1)
fonte
Use o controle de concorrência otimista .
Adicione uma coluna versionNumber ou versionTimestamp à tabela em questão (o número inteiro é mais seguro).
O usuário 1 lê o registro:
O usuário 2 lê o registro:
O usuário 1 salva o registro, isso incrementa a versão:
O usuário 2 tenta salvar o registro que lê:
O Hibernate / JPA pode fazer isso automaticamente com a
@Version
anotaçãoVocê precisa manter o estado do registro de leitura em algum lugar, geralmente na sessão (isso é mais seguro do que em uma variável de formulário oculta).
fonte
SQLAlchemy
não indica nada sobre bloqueios offline otimistas, e não consigo encontrá-lo nos documentos. Você teve um link mais útil ou apenas apontou pessoas para o SQLAlchemy em geral?Alguns sistemas ORM (Object Relational Mapping) detectam quais campos de um objeto foram alterados desde o carregamento do banco de dados e constroem a instrução de atualização SQL para definir apenas esses valores. O ActiveRecord para Ruby on Rails é um desses ORM.
O efeito líquido é que os campos que o usuário não alterou não são incluídos no comando UPDATE enviado ao banco de dados. As pessoas que atualizam campos diferentes ao mesmo tempo não substituem as alterações umas das outras.
Dependendo da linguagem de programação que você está usando, pesquise quais ORMs estão disponíveis e verifique se alguma delas atualizará apenas as colunas do banco de dados marcadas como "sujas" em seu aplicativo.
fonte