Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Implementando o bloqueio otimista no Oracle


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.