Une commande et son audit doivent être enregistrés dans
la même transaction.
process() est appelée depuis un autre bean Spring.
@Service
public class OrderService {
public void process(Order order) {
saveOrder(order); // appel interne
}
@Transactional
public void saveOrder(Order order) {
orderRepository.save(order);
auditRepository.save(
new Audit(order.getId())
);
}
}
?
Que se passe-t-il avec le @Transactional de saveOrder() ?
Dans le mode proxy standard de Spring,
@Transactional est appliqué lorsqu’un appel
traverse le proxy Spring.
Ici, process() appelle directement
saveOrder() sur la même instance.
L’appel ne repasse donc pas par le proxy et la transaction
déclarée sur saveOrder() n’est pas créée.
Le développeur peut croire que l’enregistrement de la commande et de l’audit forme une seule opération atomique. En réalité, cette transaction englobante n’existe pas dans ce chemin d’appel. Les repositories Spring Data peuvent exécuter leurs propres transactions : une première sauvegarde peut donc réussir alors qu’une opération suivante échoue.
Un @Transactional placé sur une méthode ne suffit
pas : l’appel doit passer par le proxy Spring.
Une solution courante consiste à déplacer la méthode
transactionnelle dans un autre bean Spring afin que l’appel
soit intercepté.