Dans le développement d'applications, garantir l'exclusivité d'accès aux données est souvent crucial pour éviter les conflits. Hibernate offre deux stratégies principales pour gérer cette concurrence : le verrouillage pessimiste et le verrouillage optimiste.
1. Verrouillage pessimiste
Cette approche impose un verrou dès le chargement de l'objet, qui est maintenu pendant toute la transaction jusqu'à son commit. Hibernate utilise des options de verrouillage spécifiques pour implémenter ce mécanisme, empêchant ainsi les modifications concurrentes pendant le traitement.
public void executionB() {
Session session = HibernateUtil.obtenirSession();
try {
session.beginTransaction();
Donnee objet = session.load(Donnee.class, "ref-001", LockOptions.UPGRADE);
objet.setLabel("valeur_modifiée_2");
session.getTransaction().commit();
} catch (Exception ex) {
session.getTransaction().rollback();
} finally {
HibernateUtil.fermerSession(session);
}
}
}
</div>### 2. Verrouillage optimiste
Contrairement au verrouillage pessimiste, cette méthode ne bloque pas les accès. Elle détecte les conflits au moment de la validation en comparant les versions des données. Si une modification concurrente est détectée, une expection est levée. Ce mécanisme réduit la charge sur la base de données, particulièrement pour les transactions longues.
**Fonctionnement :** Lors de la lecture, un numéro de version est récupéré. À la mise à jour, ce numéro est incrémenté et comparé à la version actuelel dans la base. Si le numéro soumis est inférieur à celui en base, la transaction est rejetée.
#### Configuration :
Ajouter un champ de version à l'entité et le mapper dans le fichier de configuration.
<div>```
public class Donnee implements Serializable {
private String identifiant;
private String libelle;
private int revision; // Champ de version pour le verrouillage optimiste
// Getters et setters
public int getRevision() { return revision; }
public void setRevision(int revision) { this.revision = revision; }
}
</div>**Cas de conflit :** Lorsque deux transactions tentent de modifier simultanément la même entité, Hibernate lance une `StaleObjectStateException`.
<div>```
public void conflitEntreTransactions() {
Session sessionA = HibernateUtil.obtenirSession();
Session sessionB = HibernateUtil.obtenirSession();
try {
Donnee objetA = sessionA.load(Donnee.class, "ref-001");
Donnee objetB = sessionB.load(Donnee.class, "ref-001");
Transaction txA = sessionA.beginTransaction();
objetA.setLabel("mise_a_jour_A");
txA.commit();
Transaction txB = sessionB.beginTransaction();
objetB.setLabel("mise_a_jour_B");
txB.commit(); // Exception lancée ici
} catch (StaleObjectStateException e) {
// Gestion de l'exception
}
}