Je ferais d'abord la différence entre les verrous optimistes et pessimistes, car ils sont différents dans leur mécanisme sous-jacent.
Le verrouillage optimiste est entièrement contrôlé par JPA et ne nécessite qu'une colonne de version supplémentaire dans les tables de base de données. Il est complètement indépendant du moteur de base de données sous-jacent utilisé pour stocker les données relationnelles.
D'autre part, le verrouillage pessimiste utilise le mécanisme de verrouillage fourni par la base de données sous-jacente pour verrouiller les enregistrements existants dans les tables. JPA a besoin de savoir comment déclencher ces verrous et certaines bases de données ne les supportent pas ou seulement partiellement.
Passons maintenant à la liste des types de verrou :
LockModeType.Optimistic
- Si les entités spécifient un champ de version, il s'agit de la valeur par défaut. Pour les entités sans colonne de version, l'utilisation de ce type de verrou n'est pas garantie de fonctionner sur n'importe quelle implémentation JPA. Ce mode est généralement ignoré comme indiqué par ObjectDB. À mon avis, il n'existe que pour que vous puissiez calculer le mode de verrouillage dynamiquement et le passer plus loin même si le verrou serait OPTIMISTIQUE à la fin. Cas d'utilisation peu probable cependant, mais c'est toujours une bonne conception d'API de fournir une option pour référencer même la valeur par défaut.
-
Exemple :
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- C'est une option rarement utilisée. Mais cela pourrait être raisonnable, si vous souhaitez verrouiller le référencement de cette entité par une autre entité. En d'autres termes, vous souhaitez verrouiller le travail avec une entité même si elle n'est pas modifiée, mais d'autres entités peuvent être modifiées par rapport à cette entité.
- Exemple :Nous avons l'entité Livre et Étagère. Il est possible d'ajouter un livre à une étagère, mais le livre n'a aucune référence à son étagère. Il est raisonnable de verrouiller l'action de déplacer un livre vers une étagère, afin qu'un livre ne se retrouve pas dans une autre étagère (du fait d'une autre transaction) avant la fin de cette transaction. Pour verrouiller cette action, il ne suffit pas de verrouiller l'entité actuelle de l'étagère du livre, car le livre n'a pas encore besoin d'être sur une étagère. Cela n'a pas non plus de sens de verrouiller toutes les étagères cibles, car elles seraient probablement différentes dans différentes transactions. La seule chose qui a du sens est de verrouiller l'entité livre elle-même, même si dans notre cas elle n'est pas modifiée (elle ne contient pas de référence à sa bibliothèque).
LockModeType.PESSIMISTIC_READ
- ce mode est similaire à
LockModeType.PESSIMISTIC_WRITE
, mais différent sur un point :jusqu'à ce qu'un verrou en écriture soit mis en place sur la même entité par une transaction, il ne doit pas bloquer la lecture de l'entité. Il permet également à d'autres transactions de se verrouiller à l'aide deLockModeType.PESSIMISTIC_READ
. Les différences entre les verrous WRITE et READ sont bien expliquées ici (ObjectDB) et ici (OpenJPA). Si une entité est déjà verrouillée par une autre transaction, toute tentative de verrouillage lèvera une exception. Ce comportement peut être modifié pour attendre un certain temps que le verrou soit libéré avant de lever une exception et d'annuler la transaction. Pour ce faire, spécifiez lejavax.persistence.lock.timeout
indice avec le nombre de millisecondes à attendre avant de lever l'exception. Il existe plusieurs façons de procéder à plusieurs niveaux, comme décrit dans le didacticiel Java EE.
LockModeType.PESSIMISTIC_WRITE
- c'est une version plus forte de
LockModeType.PESSIMISTIC_READ
. LorsqueWRITE
le verrou est en place, JPA avec l'aide de la base de données empêchera toute autre transaction de lire l'entité, pas seulement d'écrire comme avecREAD
verrouiller. - La manière dont cela est implémenté dans un fournisseur JPA en coopération avec la base de données sous-jacente n'est pas prescrite. Dans votre cas avec Oracle, je dirais qu'Oracle ne fournit pas quelque chose de proche d'un
READ
fermer à clé.SELECT...FOR UPDATE
est plutôt unWRITE
fermer à clé. Il peut s'agir d'un bogue dans hibernate ou simplement d'une décision qui, au lieu d'implémenter unREAD
"plus doux" personnalisé verrouiller, le "plus dur"WRITE
le verrou est utilisé à la place. Cela ne rompt généralement pas la cohérence, mais ne contient pas toutes les règles avecREAD
serrures. Vous pouvez exécuter des tests simples avecREAD
verrous et transactions de longue durée pour savoir si d'autres transactions peuvent acquérirREAD
se verrouille sur la même entité. Cela devrait être possible, alors que ce n'est pas le cas avecWRITE
verrous.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- c'est un autre mode de verrouillage rarement utilisé. Cependant, c'est une option où vous devez combiner
PESSIMISTIC
etOPTIMISTIC
mécanismes. Utilisation dePESSIMISTIC_WRITE
simples échouerait dans le scénario suivant :- la transaction A utilise un verrouillage optimiste et lit l'entité E
- la transaction B acquiert un verrou en écriture sur l'entité E
- la transaction B est validée et libère le verrou de E
- la transaction A met à jour E et valide
- à l'étape 4, si la colonne de version n'est pas incrémentée par la transaction B, rien n'empêche A d'écraser les modifications de B. Mode de verrouillage
LockModeType.PESSIMISTIC_FORCE_INCREMENT
forcera la transaction B à mettre à jour le numéro de version et entraînera l'échec de la transaction A avecOptimisticLockException
, même si B utilisait un verrouillage pessimiste.
- LockModeType.NONE
- il s'agit de la valeur par défaut si les entités ne fournissent pas de champ de version. Cela signifie qu'aucun verrouillage n'est activé. Les conflits seront résolus au mieux et ne seront pas détectés. C'est le seul mode de verrouillage autorisé en dehors d'une transaction