Code pour la méthode deposer du bean CDI (rappel : commit à la fin de la méthode) :
/** * Déposer un montant sur un compte. Version qui tient compte de la * concurrence. */ @Transactional (dontRollbackOn = { ConcurrentAccessException }) public void deposer(CompteBancaire compte, int montant) { int solde = compte.getSolde(); boolean concurrence = false; // Le compte est relu pour avoir la dernière valeur du solde. // (le compte a pu être modifié depuis son affichage dans la page JSF) // Il est bloqué pour empêcher d'autres éventuelles modifications. // Déblocage à la fin de l'exécution de la méthode (au commit). compte = em.find(CompteBancaire.class, compte.getId(), LockModeType.PESSIMISTIC_WRITE); if (solde != compte.getSolde()) { // le solde a été modifié ; il faut avertir l'utilisateur. concurrence = true; } compte.deposer(montant); update(compte); if (concurrence) { // le solde a été modifié ; il faut avertir l'utilisateur throw new ConcurrentAccessException("Le solde a été modifié concurremment. Le dépôt a été effectué en tenant compte du solde réel."); } }
Code similaire pour la méthode retirer
.
Code pour le backing bean :
public String enregistrerMouvement() { try { if (typeMouvement.equals("ajout")) { try { gestionnaireCompte.deposer(compte, montant); } catch(ConcurrentAccessException ex) { Util.addFlashErrorMessage(ex.getMessage()); } ...
La classe d'exception (très simplifiée) :
/** * Exception lancée en cas d'accès concurrent sans gravité. */ public class ConcurrentAccessException extends RuntimeException { public ConcurrentAccessException(String message) { super(message); } }