Devo bloquear linhas no meu banco de dados na nuvem enquanto elas estão sendo editadas por um usuário

12

Estou criando um aplicativo de desktop que persiste os dados na nuvem. Uma preocupação que tenho é começar a editar um item no aplicativo e deixá-lo por um tempo, fazendo com que os dados fiquem obsoletos. Obviamente, isso também pode acontecer se duas pessoas tentarem editar o mesmo item ao mesmo tempo. Quando eles terminam a edição e desejam salvar os dados, eu precisaria sobrescrever o que existe atualmente no banco de dados ou verificar se eles começaram a editar após a última alteração e forçá-los a descartar as alterações ou talvez dar a opção de arriscar substituindo as alterações de outra pessoa.

Pensei em adicionar um campo is_lockede lock_timestampna tabela DB. Quando um usuário começa a editar o item, a linha muda is_lockedpara true e define o registro de data e hora do bloqueio para o horário atual. Eu teria então uma quantidade de tempo durante a qual a trava é mantida (por exemplo, 5 minutos). Se alguém tentar editar o item, receberá uma mensagem informando que o item está bloqueado e quando o bloqueio expira automaticamente. Se o usuário se afastar durante a edição da trava expirará automaticamente após um período relativamente curto e, uma vez feito, o usuário será avisado de que a trava expirou e será forçado a reiniciar a edição após a atualização dos dados.

Esse seria um bom método para evitar a substituição de dados obsoletos? É um exagero (não espero que o aplicativo seja usado por mais de algumas pessoas simultaneamente em uma única conta).

(Outra preocupação que tenho são duas pessoas que travam o mesmo item, mas acredito que essa é uma condição de corrida com a qual me sinto confortável.)

yitzih
fonte
1
"Outra preocupação que tenho é que duas pessoas recebem uma trava para o mesmo item, no entanto, acredito que essa é uma condição de corrida que me agrada" - o uso de uma transação de banco de dados em torno da aquisição da trava deve impedir essas condições de corrida.
Jules
A maioria dos mecanismos de banco de dados (do tipo relacional, pelo menos) tem suporte embutido para isso. É um conceito muito comum no mundo do RDBMS, e até os bancos de dados "de brinquedo" o tratam bem o suficiente, desde que você diga que deseja um bloqueio otimista ou pessimista. De qualquer forma, não acho que seja algo que você precise construir por qualquer meio: verifique as opções no seu mecanismo db para ver como trabalhar com ele.
Jleach # 9/18
O fato de seu aplicativo ser um aplicativo de desktop (um cliente gordo ) não faz muita diferença. Ele pode ser projetado da mesma maneira que um aplicativo de servidor de várias instâncias altamente disponível.
Hosam Aly

Respostas:

19

Uma coisa que irá ajudá-lo aqui é a terminologia. O que você está descrevendo aqui é chamado de 'bloqueio pessimista'. A principal alternativa a essa abordagem é o 'bloqueio otimista'. No bloqueio pessimista, cada ator deve bloquear o registro antes de atualizá-lo e liberar o bloqueio quando a atualização estiver concluída. No bloqueio otimista, você assume que ninguém mais está atualizando o registro e tentando. A atualização falha se o registro foi alterado por algum outro ator.

Geralmente, o bloqueio otimista é preferível se a chance de dois atores atualizarem a mesma coisa ao mesmo tempo for baixa. O pessimista geralmente é usado quando essa chance é alta ou você precisa saber que sua atualização será bem-sucedida antes do início. Na minha experiência, o bloqueio otimista é quase sempre preferível, porque há muitos problemas inerentes ao bloqueio pessimista. Um dos maiores problemas foi abordado na sua pergunta. Os usuários podem bloquear um registro para edição e depois sair para o almoço. Sua mitigação ajudará nisso, mas a experiência do usuário não será melhor que a abordagem otimista e provavelmente será muito pior. Por exemplo, um usuário abre um registro, começa a atualizá-lo e seu chefe aparece em sua mesa. Outro usuário tenta editar o registro. Está trancado. O segundo usuário continua tentando e, após 5 minutos, o bloqueio expira e o segundo usuário atualiza o registro. O primeiro usuário volta à tela, tenta salvar e é avisado que perdeu o bloqueio. Agora, no mesmo cenário, com tudo a mesma coisa, exceto com o bloqueio otimista, a experiência do primeiro usuário é praticamente a mesma, mas o segundo usuário não espera 5 minutos.

O esquema que você apresentou seria muito melhorado com a implementação de bloqueio otimista para o valor de bloqueio, mas meu palpite é que o bloqueio otimista provavelmente é bom para a coisa toda e você pode se livrar do campo is_locked.

Você não fornece o 'banco de dados em nuvem' que está usando. Você provavelmente deve examinar os recursos para verificar se há recursos internos para isso antes de implementar sua própria solução.

Aqui está a receita básica: em vez de um campo is_locked, tenha um campo de número de versão. Quando você recupera o registro, você extrai a versão atual do registro. Quando você atualiza, a atualização depende do campo da versão que corresponde ao que você recuperou e o incrementa com êxito. Se a versão não corresponder, a atualização não terá efeito e você a reportará como uma falha.

JimmyJames
fonte
Esta é uma resposta muito útil. Você pode explicar por que o bloqueio pessimista é desencorajado quando há uma pequena chance de "colisões". É apenas porque requer que o banco de dados inicie a edição, ou por complexidade extra ou por algum outro motivo? Obrigado!
yitzih
3
@yitzih Algumas sugestões de leitura: Fowler et al, Patterns of Enterprise Application Architecture . Há um capítulo inteiro sobre essa questão, com uma boa discussão de todas as opções e razões para escolhê-las.
Jules
2
@ Jimmy - Sua resposta está bem. Em alguns casos, relatar um erro de volta não é suficiente. Considere um caso em que um usuário gasta alguns minutos atualizando um registro. Nesse caso, apenas falhar pode não ser bom o suficiente, pode-se dar ao usuário a oportunidade de mesclar suas alterações a bordo com as cometidas pelo outro usuário. Eu deveria ter dito que o bloqueio otimista pode exigir resolução de conflitos, dependendo de seus requisitos.
22618 Jon Jonnor
3
Vale ressaltar que o bloqueio pessimista é muito mais fácil de explicar ao cliente. Se você escrever uma mensagem informando que o cliente não pode acessar o registro porque está sendo editado por outro, o cliente entenderá perfeitamente e geralmente o aceita. Se você informar ao cliente após salvar que o salvamento não foi possível porque já foi atualizado por outro usuário, 7/10, o cliente ficará frustrado e / ou esperará explicações para esse comportamento estranho do programa.
Neil
2
@ Neil Isso é verdade e acho que muitas vezes o bloqueio pessimista é usado quando o otimista é mais apropriado. Geralmente, o fluxo de trabalho torna muito improvável a ocorrência de uma colisão.
JimmyJames
0

A partir da resposta de @ JimmyJames , podemos ver como a pergunta é realmente sobre a experiência do usuário .

Tudo depende do contexto. Quanto tempo e esforço são necessários para atualizar um registro? Com que frequência vários usuários desejam atualizar o mesmo documento?

Por exemplo, se seus usuários normalmente levam alguns segundos para atualizar o registro e há pouca disputa, provavelmente o bloqueio otimista é o caminho a percorrer. Na pior das hipóteses, um usuário terá que gastar mais alguns segundos, talvez até um minuto, para atualizar um documento.

Se o seu documento é altamente controverso, mas bem estruturado, talvez você possa permitir que eles bloqueiem campos individuais em incrementos de 30 segundos, mostrando um cronômetro ou uma notificação discreta para permitir que eles estendam o bloqueio.

No entanto, se seus usuários gastam uma quantidade considerável de tempo ou esforço, considere outras abordagens. Seu registro está bem estruturado? Você poderia mostrar aos usuários uma comparação (uma diferença) entre a versão no servidor e a versão que eles estão tentando salvar? Você pode destacar as diferenças? Você pode deixá-los fundir as mudanças? Pense na experiência que você deseja ter com suas ferramentas de controle de origem. Você realmente não quer ser forçado a escrever todo esse código novamente!

Você pode consultar o Google Docs para obter inspiração adicional. Talvez você possa mostrar aos usuários uma notificação de que uma nova versão foi salva. Talvez você possa mostrar a eles quantas pessoas têm o registro aberto, para que possam optar por voltar em um momento menos controverso.

Hosam Aly
fonte