Je suis nouveau dans Spring Transaction. Quelque chose que j'ai trouvé vraiment étrange, je l'ai probablement bien compris.
Je voulais avoir une méthode transactionnelle autour du niveau de la méthode et j'ai une méthode d'appel dans la même classe et il semble que cela n'aime pas ça, elle doit être appelée depuis la classe séparée. Je ne comprends pas comment cela est possible.
Si quelqu'un a une idée de la façon de résoudre ce problème, je l'apprécierais grandement. Je voudrais utiliser la même classe pour appeler la méthode transactionnelle annotée.
Voici le code:
public class UserService {
@Transactional
public boolean addUser(String userName, String password) {
try {
// call DAO layer and adds to database.
} catch (Throwable e) {
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
}
}
public boolean addUsers(List<User> users) {
for (User user : users) {
addUser(user.getUserName, user.getPassword);
}
}
}
java
spring
aspectj
spring-aop
Mike
la source
la source
TransactionTemplate
approche: stackoverflow.com/a/52989925/355438Réponses:
C'est une limitation de Spring AOP (objets dynamiques et cglib ).
Si vous configurez Spring pour utiliser AspectJ pour gérer les transactions, votre code fonctionnera.
La solution la plus simple et probablement la meilleure consiste à refactoriser votre code. Par exemple, une classe qui gère les utilisateurs et une qui traite chaque utilisateur. Ensuite , la gestion des transactions par défaut avec Spring AOP fonctionnera.
Conseils de configuration pour gérer les transactions avec AspectJ
Pour permettre à Spring d'utiliser AspectJ pour les transactions, vous devez définir le mode sur AspectJ:
Si vous utilisez Spring avec une version antérieure à 3.0, vous devez également l'ajouter à votre configuration Spring:
la source
Le problème ici est que les proxys AOP de Spring ne s'étendent pas, mais enveloppent plutôt votre instance de service pour intercepter les appels. Cela a pour effet que tout appel à "this" depuis votre instance de service est directement invoqué sur cette instance et ne peut pas être intercepté par le proxy d'encapsulation (le proxy n'est même pas au courant d'un tel appel). Une solution est déjà mentionnée. Une autre astuce serait simplement de demander à Spring d'injecter une instance du service dans le service lui-même et d'appeler votre méthode sur l'instance injectée, qui sera le proxy qui gère vos transactions. Mais sachez que cela peut également avoir de mauvais effets secondaires, si votre bean service n'est pas un singleton:
la source
UserService
a une portée singleton? Et si c'était le même objet?Avec Spring 4, il est possible d'auto-câblé
la source
À partir de Java 8, il existe une autre possibilité, que je préfère pour les raisons données ci-dessous:
Cette approche présente les avantages suivants:
1) Il peut être appliqué aux méthodes privées . Vous n'avez donc pas à interrompre l'encapsulation en rendant une méthode publique juste pour satisfaire les limitations de Spring.
2) La même méthode peut être appelée dans une propagation de transaction différente et il appartient à l'appelant de choisir celle qui convient. Comparez ces 2 lignes:
3) Il est explicite, donc plus lisible.
la source
TransactionHandler
tant que sous-classe et que la sous-classe fait appel à ces deux méthodes dans laTransactionHandler
super classe, pourrai-je toujours bénéficier des avantages de@Transactional
comme prévu?Voici ma solution pour l' auto-invocation :
la source
Vous pouvez installer automatiquement BeanFactory dans la même classe et faire un
getBean(YourClazz.class)
Il proxifiera automatiquement votre classe et prendra en compte votre @Transactional ou autre annotation aop.
la source
Le problème est lié à la façon dont les classes de charge de ressort et les proxys. Cela ne fonctionnera pas tant que vous n'écrivez pas votre méthode / transaction interne dans une autre classe ou que vous n'allez pas dans une autre classe, puis que vous revenez à votre classe et que vous n'écrivez pas la méthode de transcation imbriquée interne.
Pour résumer, les proxys de printemps ne permettent pas les scénarios auxquels vous êtes confrontés. vous devez écrire la 2ème méthode de transaction dans une autre classe
la source
Voici ce que je fais pour les petits projets avec une utilisation marginale des appels de méthode dans la même classe. La documentation dans le code est fortement conseillée, car elle peut sembler étrange aux collègues. Mais cela fonctionne avec des singletons , est facile à tester, simple, rapide à réaliser et m'épargne l'instrumentation AspectJ à part entière. Cependant, pour une utilisation plus intensive, je conseillerais la solution AspectJ comme décrit dans la réponse d'Espens.
la source