Explication du message d'erreur pour les accès concurrents

Le message d'erreur est de ce type (j'ai mis en valeur les passages importants) :

AVERTISSEMENT:   #{mouvement.enregistrerMouvement()}: /mouvement.xhtml @48,62 action="#{mouvement.enregistrerMouvement()}": jakarta.persistence.OptimisticLockException: Exception [EclipseLink-5010] (Eclipse Persistence Services - 4.0.0-M3.payara-p1.v202206011138): org.eclipse.persistence.exceptions.OptimisticLockException
Exception Description: The object [fr.grin.tpbanque.entity.CompteBancaire[ id=3 ]] cannot be merged because it has changed or been deleted since it was last read. 
Class> fr.grin.tpbanque.entity.CompteBancaire
jakarta.faces.FacesException: #{mouvement.enregistrerMouvement()}: /mouvement.xhtml @48,62 action="#{mouvement.enregistrerMouvement()}": jakarta.persistence.OptimisticLockException: Exception [EclipseLink-5010] (Eclipse Persistence Services - 4.0.0-M3.payara-p1.v202206011138): org.eclipse.persistence.exceptions.OptimisticLockException
Exception Description: The object [fr.grin.tpbanque.entity.CompteBancaire[ id=3 ]] cannot be merged because it has changed or been deleted since it was last read. 
Class> fr.grin.tpbanque.entity.CompteBancaire
	at com.sun.faces.application.ActionListenerImpl.getNavigationOutcome(ActionListenerImpl.java:83)
   ...
Caused by: jakarta.el.ELException: /mouvement.xhtml @48,62 action="#{mouvement.enregistrerMouvement()}": jakarta.persistence.OptimisticLockException: Exception [EclipseLink-5010] (Eclipse Persistence Services - 4.0.0-M3.payara-p1.v202206011138): org.eclipse.persistence.exceptions.OptimisticLockException
Exception Description: The object [fr.grin.tpbanque.entity.CompteBancaire[ id=3 ]] cannot be merged because it has changed or been deleted since it was last read. 
Class> fr.grin.tpbanque.entity.CompteBancaire
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:76)
	at com.sun.faces.application.ActionListenerImpl.getNavigationOutcome(ActionListenerImpl.java:74)
	... 36 more
Caused by: jakarta.persistence.OptimisticLockException: Exception [EclipseLink-5010] (Eclipse Persistence Services - 4.0.0-M3.payara-p1.v202206011138): org.eclipse.persistence.exceptions.OptimisticLockException
Exception Description: The object [fr.grin.tpbanque.entity.CompteBancaire[ id=3 ]] cannot be merged because it has changed or been deleted since it was last read. 
Class> fr.grin.tpbanque.entity.CompteBancaire
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.mergeInternal(EntityManagerImpl.java:646)
	at org.eclipse.persistence.internal.jpa.EntityManagerImpl.merge(EntityManagerImpl.java:622)
	at com.sun.enterprise.container.common.impl.EntityManagerWrapper.merge(EntityManagerWrapper.java:307)
	at fr.grin.tpbanque.service.GestionnaireCompte.update(GestionnaireCompte.java:76)
	at fr.grin.tpbanque.service.GestionnaireCompte$Proxy$_$$_WeldSubclass.update(Unknown Source)
	at fr.grin.tpbanque.service.GestionnaireCompte.retirer(GestionnaireCompte.java:106)
	at fr.grin.tpbanque.service.GestionnaireCompte$Proxy$_$$_WeldSubclass.retirer$$super(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

L'exception première est une OptimisticLockException. La ligne qui a provoqué l'erreur correspond à l'instruction update(compteBancaire) de GestionnaireCompte. En fait, c'est la méthode merge de EntityManager (plus exactement de la classe EntityManagerImpl fournie par EclipseLink qui implémente EntityManager) appelée par update, qui provoque l'erreur.

[ Au passage, vous pouvez remarquer, comme il est expliqué dans le cours, que c'est la méthode update d'un proxy de GestionnaireCompte qui est appelé avant l'appel de update de GestionnaireCompte. ]

Le déroulement des faits :

  1. L'erreur a lieu dans N1 car il a été le premier à récupérer le compte bancaire de Ringo Starr. Il a récupéré en même temps son numéro de version, disons 45.
  2. Ensuite N2 récupère le même compte avec le même numéro de version. N2 modifie le compte. Au moment de l'enregistrement le numéro de version est 45 et donc tout est correct. Cette modification passe le numéro de version à 46.
  3. Lorsque N1 modifie le compte et veut enregistrer la modification, JPA constate que le numéro de version actuel (46) n'est pas égal à celui au moment de la récupération du compte dans la base (45). Donc le compte a été modifié concuremment et une exception est lancée pour éviter les problèmes liés aux accès concurrents.