143 votes

Printemps @Transaction appel de méthode par la méthode au sein de la même classe, ne fonctionne pas?

Je suis nouveau sur le Printemps de la Transaction. Quelque chose que j'ai trouvé vraiment bizarre, probablement, je ne comprenez cela correctement. Je voulais avoir un transactionnelles autour au niveau de la méthode et j'ai un appelant de la méthode au sein de la même classe et il me semble qu'il n'aime pas cela, elle doit être appelée à partir de la classe distincte. Je ne comprends pas comment c'est possible. Si quelqu'un a une idée de comment résoudre ce problème, je vous serais très reconnaissant. Je voudrais utiliser la même classe d'appeler le annoté de la méthode.

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);
        }
    } 
}

112voto

Espen Points 5898

C'est une limitation avec Spring AOP. (objets dynamiques et CGLIB)

Si vous configurez Printemps à l'utilisation AspectJ pour gérer les transactions, votre code fonctionne.

La simple et probablement la meilleure alternative est de restructurer le code. Par exemple, une classe qui gère les utilisateurs et les une que les processus de chaque utilisateur. Par défaut la gestion des transactions avec Spring AOP fonctionne.

Conseils de Configuration pour le traitement des transactions avec AspectJ

Pour activer Printemps à l'utilisation AspectJ pour les transactions, vous devez définir le mode d'AspectJ:

<tx:annotation-driven mode="aspectj"/>

Si vous êtes à l'aide de Printemps avec une version antérieure à la version 3.0, vous devez également ajouter à votre configuration Spring:

<bean class="org.springframework.transaction.aspectj
        .AnnotationTransactionAspect" factory-method="aspectOf">
    <property name="transactionManager" ref="transactionManager" />
</bean>

66voto

Kai Points 121

Le problème, ici, c'est que le Printemps de l'AOP procurations ne pas prolonger, mais plutôt l'enveloppe de votre instance de service à intercepter les appels. Cela a pour effet, que tout appel au "présent" à l'intérieur de votre instance de service est appelée directement sur l'instance et ne peuvent être interceptées par l'emballage proxy (proxy n'est même pas au courant de cet appel). L'une des solutions est déjà mentionné. Une autre chouette on serait tout simplement de Printemps injecter une instance du service dans le service lui-même, et appelez votre méthode sur l'injection d'instance, qui sera le proxy qui gère vos transactions. Mais sachez que cela peut avoir aussi des effets secondaires néfastes, si votre service de haricot n'est pas un singleton:

<bean id="userService" class="your.package.UserService">
  <property name="self" ref="userService" />
    ...
</bean>

public class UserService {
    private UserService self;

    public void setSelf(UserService self) {
        this.self = self;
    }

    @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) {
            self.addUser(user.getUserName, user.getPassword);
        }
    } 
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X