Eu primeiro diferenciaria entre bloqueios otimistas e pessimistas, porque eles são diferentes em seu mecanismo subjacente.
O bloqueio otimista é totalmente controlado pelo JPA e requer apenas uma coluna de versão adicional nas tabelas de banco de dados. É completamente independente do mecanismo de banco de dados subjacente usado para armazenar dados relacionais.
Por outro lado, o bloqueio pessimista usa o mecanismo de bloqueio fornecido pelo banco de dados subjacente para bloquear os registros existentes nas tabelas. O JPA precisa saber como acionar esses bloqueios e alguns bancos de dados não os suportam ou os suportam apenas parcialmente.
Agora para a lista de tipos de bloqueio:
LockModeType.Optimistic
- Se as entidades especificarem um campo de versão, este será o padrão. Para entidades sem uma coluna de versão, não é garantido que o uso desse tipo de bloqueio funcione em qualquer implementação de JPA. Esse modo geralmente é ignorado conforme declarado pelo ObjectDB. Na minha opinião, ele só existe para que você possa calcular o modo de bloqueio dinamicamente e passá-lo ainda mais, mesmo que o bloqueio seja OTIMISTA no final. No entanto, não é um caso de uso muito provável, mas é sempre um bom design de API fornecer uma opção para referenciar até mesmo o valor padrão.
-
Exemplo:
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- Esta é uma opção raramente usada. Mas pode ser razoável, se você quiser bloquear a referência a essa entidade por outra entidade. Em outras palavras, você deseja bloquear o trabalho com uma entidade mesmo que ela não seja modificada, mas outras entidades podem ser modificadas em relação a essa entidade.
- Exemplo:temos a entidade Book and Shelf. É possível adicionar Livro à Estante, mas o livro não tem nenhuma referência à sua estante. É razoável bloquear a ação de mover um livro para uma estante, para que um livro não acabe em outra estante (devido a outra transação) antes do final desta transação. Para bloquear esta ação, não é suficiente bloquear a entidade da estante de livros atual, pois o livro ainda não precisa estar em uma estante. Também não faz sentido bloquear todas as estantes de destino, pois elas provavelmente seriam diferentes em transações diferentes. A única coisa que faz sentido é bloquear a própria entidade do livro, mesmo que no nosso caso ela não seja alterada (ela não mantém referência à sua estante).
LockModeType.PESSIMISTIC_READ
- este modo é semelhante a
LockModeType.PESSIMISTIC_WRITE
, mas diferente em uma coisa:até que o bloqueio de gravação esteja em vigor na mesma entidade por alguma transação, ele não deve bloquear a leitura da entidade. Ele também permite que outras transações sejam bloqueadas usandoLockModeType.PESSIMISTIC_READ
. As diferenças entre os bloqueios WRITE e READ são bem explicadas aqui (ObjectDB) e aqui (OpenJPA). Se uma entidade já estiver bloqueada por outra transação, qualquer tentativa de bloqueá-la lançará uma exceção. Esse comportamento pode ser modificado para aguardar algum tempo para que o bloqueio seja liberado antes de lançar uma exceção e reverter a transação. Para fazer isso, especifique ojavax.persistence.lock.timeout
dica com o número de milissegundos a esperar antes de lançar a exceção. Há várias maneiras de fazer isso em vários níveis, conforme descrito no tutorial Java EE.
LockModeType.PESSIMISTIC_WRITE
- esta é uma versão mais forte de
LockModeType.PESSIMISTIC_READ
. QuandoWRITE
lock está em vigor, JPA com a ajuda do banco de dados impedirá qualquer outra transação de ler a entidade, não apenas para escrever como comREAD
bloqueio. - A maneira como isso é implementado em um provedor JPA em cooperação com o banco de dados subjacente não é prescrita. No seu caso com o Oracle, eu diria que o Oracle não fornece algo próximo a um
READ
trancar.SELECT...FOR UPDATE
é realmente umWRITE
trancar. Pode ser um bug na hibernação ou apenas uma decisão que, em vez de implementar oREAD
personalizado "mais suave" lock, o "mais difícil"WRITE
bloqueio é usado em seu lugar. Isso geralmente não quebra a consistência, mas não mantém todas as regras comREAD
fechaduras. Você pode executar alguns testes simples comREAD
bloqueios e transações de longa duração para descobrir se mais transações podem adquirirREAD
bloqueios na mesma entidade. Isso deve ser possível, mas não comWRITE
fechaduras.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- este é outro modo de bloqueio raramente usado. No entanto, é uma opção onde você precisa combinar
PESSIMISTIC
eOPTIMISTIC
mecanismos. UsandoPESSIMISTIC_WRITE
simples falharia no seguinte cenário:- transação A usa bloqueio otimista e lê a entidade E
- transação B adquire bloqueio WRITE na entidade E
- transação B confirma e libera bloqueio de E
- transação A atualiza E e confirma
- na etapa 4, se a coluna de versão não for incrementada pela transação B, nada impedirá que A substitua as alterações de B. Modo de bloqueio
LockModeType.PESSIMISTIC_FORCE_INCREMENT
forçará a transação B a atualizar o número da versão e fará com que a transação A falhe comOptimisticLockException
, embora B estivesse usando um bloqueio pessimista.
- LockModeType.NONE
- este é o padrão se as entidades não fornecerem um campo de versão. Isso significa que nenhum bloqueio está habilitado os conflitos serão resolvidos com base no melhor esforço e não serão detectados. Este é o único modo de bloqueio permitido fora de uma transação