Dans une même classe, un appel d'une méthode transactionnelle à une méthode non transactionnelle peut fonctionner correctement. En revanche, le cas contraire où la transaction échoue est illustré par le point 4 ci-dessous (appel interne dans une même classe).
@Autowired
private XXXMapper xxxMapper;
@Autowired
private YYYMapper yyyMapper;
@Transactional
public ResultVO<AssetChangeVO> modifyAssetDetail() {
xxxMapper.execute();
}
private void copyYYY() {
yyyMapper.copy("src", "dest");
}
- Introduction
-
- La classe de service n'est pas gérée par Spring
-
- Aucun gestionnaire de transactions configuré dans le fichier Spring
-
- Méthode transactionnelle marquée
finaloustatic
- Méthode transactionnelle marquée
-
- Appel interne dans une même classe
-
- Visibilité de la méthode autre que
public
- Visibilité de la méthode autre que
-
- Moteur de stockage de la base ne supportant pas les transactions
-
- Annotation
@Transactionalmal configurée
- Annotation
-
- Délai d'expiration trop court
-
- Mécanisme de propagation erroné
-
- Attribut
rollbackForincorrect
- Attribut
-
- Annotation de transaction écrasée
-
- Piège des transactions imbriquées
-
- Appel multi-thread dans une transaction
-
- Expection capturée sans être relancée
-
- Exception différente lancée manuellement
Introduction
Dans le développement quotidien, nous utilisons fréquemment les transactions Spring. Récemment, un ami a été interrogé lors d'un entretien chez Meituan sur le sujet : Dans quels cas une transaction Spring ne fonctionne-t-elle pas ? Aujourd'hui, nous allons passer en revue 15 scénarios où les transactions Spring échouent.
1. La classe de service n'est pas gérée par Spring
// @Service (commenté)
public class DemoServiceImpl implements DemoService {
@Autowired
private DemoMapper demoMapper;
@Autowired
private LogMapper logMapper;
@Transactional
public void addDemo(Demo demo) {
demoMapper.insert(demo);
logMapper.insert(buildLog(demo));
}
}
- Cause de l'échec : Dans l'exemple ci-dessus, l'annotation
@Serviceest commentée. La transaction Spring (@Transactional) ne s'applique pas car Spring utilise l'AOP pour créer un proxy de la classe cible afin de supporter les transactions. Or, si la classe n'est pas gérée par Spring (pas de@Service), aucun proxy n'est créé. - Solution : Ajouter l'annotation
@Service.
2. Aucun getsionnaire de transactions configuré dans le fichier Spring
@Configuration
public class AppConfig {
// Pas de gestionnaire de transactions
}
@Service
public class MyService {
@Transactional
public void doSomething() {
// ...
}
}
- Cause de l'échec : Aucun gestionnaire de transactions n'est défini dans
AppConfig. Spring ne peut donc pas créer l'objet proxy transactionnel, et l'annotation@Transactionalreste ignorée. - Solution : Configurer un
PlatformTransactionManagerdans la classe de configuraton :
@Configuration
public class AppConfig {
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}
@Service
public class MyService {
@Transactional
public void doSomething() {
// ...
}
}
Pour un projet Spring Boot, la configuration automatique active généralement le gestionnaire de transactions par défaut.
3. Méthode transactionnelle marquée final ou static
@Service
public class DemoServiceImpl {
@Autowired
private DemoMapper demoMapper;
@Autowired
private LogMapper logMapper;
@Transactional
public final void addDemo(Demo demo) {
demoMapper.insert(demo);
logMapper.insert(buildLog(demo));
}
}
- Cause de l'échec : Une méthode déclarée
finaloustaticne peut pas être redéfinie dans une sous-classe. Or, le proxy dynamique de Spring nécessite la redéfinition pour intercepter l'appel et ajouter le comportement transactionnel. Par conséquent, la transaction est ignorée. - Solution : Supprimer les modificateurs
finaletstaticdes méthodes transactionnelles.