Existem duas abordagens gerais para o bloqueio.
Primeiro, você tem um bloqueio pessimista. Nesta abordagem, você bloqueia a linha (
SELECT ... FOR UPDATE
) que impede qualquer outra pessoa de alterar a linha. Então você faz o UPDATE
. Quando você confirma sua alteração, o bloqueio é liberado. Não há necessidade neste caso de ter uma coluna de número de versão/ timestamp (pelo menos não para suportar travamento) e o código é relativamente fácil. A desvantagem do bloqueio pessimista é que você precisa manter o bloqueio o tempo todo em que um usuário estiver sentado em uma página potencialmente editando dados. Isso é tecnicamente muito difícil se você estiver criando um aplicativo baseado na Web, pois o HTTP é um protocolo sem estado. A solicitação que renderiza inicialmente a página normalmente obteria uma conexão do pool de conexões, faça o
SELECT
e, em seguida, retorne a conexão ao pool assim que a página for concluída. A solicitação subsequente para atualizar os dados geralmente ocorre em uma conexão diferente com uma sessão de banco de dados diferente, portanto, você não pode bloquear a linha na primeira sessão e atualizá-la na segunda. Se você quisesse bloquear a linha de forma pessimista, precisaria fazer muito trabalho no back-end para garantir que uma conexão de banco de dados estivesse vinculada a uma sessão de camada intermediária específica até que o usuário terminasse de editar os dados. Isso geralmente tem impactos muito negativos na escalabilidade e apresenta todos os tipos de problemas de gerenciamento de sessão - como você sabe, por exemplo, se solicitei uma página, bloqueei uma linha e fechei meu navegador sem fazer logout ou fazer uma alteração? Por quanto tempo você vai deixar o registro bloqueado no banco de dados? O que acontece se alguma outra sessão estiver tentando bloquear a linha? Por quanto tempo você vai deixar aquela sessão bloquear esperando por um bloqueio se a primeira pessoa saiu para almoçar? Geralmente, as pessoas não implementam o bloqueio pessimista em aplicativos baseados na Web porque o gerenciamento de sessões e estado de sessão é muito impraticável. A segunda opção é o bloqueio otimista. Nesta abordagem, você adiciona um número de versão/ carimbo de data/hora à linha. Você seleciona esse número de versão/ carimbo de data/hora ao consultar os dados. Então você usa isso em seu
WHERE
quando você fizer a atualização posteriormente e verificar quantas linhas foram realmente modificadas. Se você modificar exatamente uma linha, saberá que a linha não mudou desde que a leu. Se você modificar 0 linhas, saberá que a linha foi alterada e poderá lidar com o erro. Assim, por exemplo, você selecionaria os dados junto com o número da versão
SELECT address_line1, city, state, zip, version
FROM addressTable
WHERE address_id = `<<some key>>`
Quando você estivesse pronto para fazer a atualização, faria algo assim, usando a
version
em seu UPDATE
e lançar um erro se a linha mudou UPDATE addressTable
SET address_line1 = `<<new address line 1>>`,
city = `<<new city>>`,
state = `<<new state>>`,
zip = `<<new zip>>`,
version = version + 1
WHERE address_id = `<<some key>>`
AND version = `<<version you read initially>>`
IF( SQL%ROWCOUNT = 0 )
THEN
-- Darn. The row must have changed since you read it. Do something to
-- alert the user. Most likely, the application will need to re-query the
-- data to see what the address has been changed to and then ask the user
-- whether they want to re-apply the changes.
RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;
Seu aplicativo faria algo útil com o erro. Normalmente, isso significaria fazer algo como consultar os dados novamente, apresentar as alterações ao usuário e perguntar se ele ainda deseja aplicar suas alterações. Se, por exemplo, eu leio um endereço e começo a editá-lo, vou almoçar, meu colega faz login, lê o mesmo endereço, faz algumas edições e salva, então eu volto e tento salvar minhas alterações, geralmente faria sentido para me mostrar algo dizendo que meu colega já mudou o endereço para algo novo-- quero continuar fazendo edições ou quero abandoná-las.