2024-12-13
Problèmes d’Isolation
Dirty Read: Lecture d’une donnée non validée (transaction non committée)
Non-Repeatable Read: Deux lectures successives donnent des résultats différents
Phantom Read: Nouvelles lignes apparaissent entre deux lectures
Lost Update: Écrasement d’une mise à jour par une autre transaction
Niveaux d’Isolation
READ_UNCOMMITTED - Plus bas niveau - Permet tous les problèmes - Performance maximale
READ_COMMITTED - Empêche dirty reads - Niveau par défaut - Bon compromis
REPEATABLE_READ - Empêche non-repeatable reads - Verrouillage lecture - Impact modéré
SERIALIZABLE - Isolation maximale - Empêche phantom reads - Performance réduite
Transactions Locales
Transactions Distribuées
UserTransactionTransactionManagerDu EJB au CDI
Remplacement progressif
| EJB | CDI | Commentaires |
|---|---|---|
| @Stateless | @ApplicationScoped | Sans état |
| @Stateful | @SessionScoped | Avec état |
| @Singleton | @ApplicationScoped + @Singleton | Instance unique |
| @EJB | @Inject | Injection |
| @TransactionAttribute | @Transactional | Transactions |
| @Schedule | @Scheduled | Timers |
Gestion Programmatique - Contrôle explicite par injection de UserTransaction - Style impératif - Granularité fine - Flexibilité maximale
Gestion Déclarative - Annotations @Transactional - Style déclaratif - Configuration simple - Gestion automatique
@Transactional Overview@Transactional(
//Type de transaction
//Les même que pour les EJB
value = TxType.REQUIRED, //Défaut
// Déclenche un rollback sur ces exceptions
rollbackOn = { SQLException.class },
// Ne déclenche pas de rollback sur ces exceptions
dontRollbackOn = { CustomException.class }
// Par défaut, toutes les exceptions déclenchent un rollback
)
public class CompteService {
public void transfer(long from, long to, BigDecimal amount) {
// Logique de transfert
}
}Niveau Classe
Priorités d’Application
Niveau Méthode
Considérations
@TransactionalAttributs de Base
Gestion des Exceptions
:::
@RequestScoped
public class CompteBean {
@PersistenceContext
private EntityManager em;
@Transaction(TxType.REQUIRED)
public void transferer(Long sourceId, Long destId, BigDecimal montant) {
Compte source = em.find(Compte.class, sourceId);
Compte dest = em.find(Compte.class, destId);
if (source.getSolde().compareTo(montant) < 0) {
throw new SoldeInsuffisantException();
}
source.setSolde(source.getSolde().subtract(montant));
dest.setSolde(dest.getSolde().add(montant));
em.merge(source);
em.merge(dest);
}
@Transaction(TxType.REQUIRES_NEW)
public void journaliser(String operation) {
Journal journal = new Journal();
journal.setOperation(operation);
journal.setDate(LocalDateTime.now());
em.persist(journal);
}
}@Transactional par CDI (interceptor)@Transactional?@Transactional(REQUIRED)@Transactional(SUPPORTS)@TransactionScoped
@Named
public class TransactionBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<Operation> operations = new ArrayList<>();
public void addOperation(Operation op) {
operations.add(op);
}
// Le bean et ses données persistent pendant toute la transaction
}E. Bruno - Transactions en Jakarta Enterprise Edition