Après avoir introduit l'annotation @Transactional pour contrôler les transactions, examinons deux attributs essentiels :
rollbackFor: Définit les types d'exception déclanchant un rollbackpropagation: Contrôle le comportement de propagation des transactions
1.3.1 rollbackFor
Par défaut, Spring ne rollback que pour les RuntimeException. Observons ce comportement :
@Transactional
public void supprimerEntite(Integer identifiant) {
// Suppression de l'entité principale
entiteRepo.effacer(identifiant);
// Simulation d'exception
int calcul = identifiant / 0;
// Nettoyage des dépendances
dependanceRepo.supprimerParEntite(identifiant);
}
L'exception arithmétique provoque un rollback. Mais avec une exception vérifiée :
@Transactional
public void supprimerEntite(Integer identifiant) throws Exception {
entiteRepo.effacer(identifiant);
if(true) {
throw new Exception("Erreur critique");
}
dependanceRepo.supprimerParEntite(identifiant);
}
Contrairement aux attentes, la transaction est validée malgré l'exception. Solution :
@Transactional(rollbackFor = Exception.class)
public void supprimerEntite(Integer identifiant) {
entiteRepo.effacer(identifiant);
int test = identifiant / 0; // Exception runtime
dependanceRepo.supprimerParEntite(identifiant);
}
Cette configuration assure le rollback pour toutes les exceptions.
1.3.3 propagation
Définit comment les transactions interagissent entre méthodes transactionnelles.
| Valeur | Comportement |
|---|---|
| REQUIRED (défaut) | Rejoint une transaction existante ou en crée une nuovelle |
| REQUIRES_NEW | Crée toujours une nouvelle transaction |
| SUPPORTS | Rejoint une transaction si elle existe |
| NOT_SUPPORTED | Exécute hors transaction |
1.3.3.2 Étude de cas
Requête : Journaliser les suppressions de département même en cas d'échec.
@Transactional(rollbackFor = Exception.class)
public void dissoudreDepartement(Integer id) {
try {
departementRepo.supprimer(id);
if(true) throw new Exception("Erreur");
employeRepo.supprimerParDepartement(id);
} finally {
Journal journal = new Journal(
LocalDateTime.now(),
"Suppression département: " + id
);
journalService.enregistrer(journal);
}
}
@Service
public class JournalServiceImpl implements JournalService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void enregistrer(Journal entree) {
journalRepo.inserer(entree);
}
}
Avec REQUIRES_NEW, l'entrée de journal est persistée même si la transaction principale échoue.
Cas d'usage :
- REQUIRED : Comportement transactionnel standard
- REQUIRES_NEW : Opérations critiques nécessitant une persistance garantie