Où devrais-je mettre @Transactional annotation: à une définition d'interface ou à une classe d'implémentation?

La question du titre dans le code:

@Transactional (readonly = true)
public interface FooService {
   void doSmth ();
}


public class FooServiceImpl implements FooService {
   ...
}

Vs

public interface FooService {
   void doSmth ();
}

@Transactional (readonly = true)
public class FooServiceImpl implements FooService {
   ...
}
66
demandé sur Roman 2010-06-25 21:41:40

6 réponses

À Partir de http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

La recommandation de L'équipe Spring est que vous annotez uniquement des classes concrètes avec l'annotation @Transactional, par opposition à l'annotation des interfaces. Vous pouvez certainement placer l'annotation @Transactional sur une interface (ou une méthode d'interface), mais cela ne fonctionnera que comme vous le feriez si vous utilisez des proxies basés sur l'interface. Le fait que les annotations ne soient pas inherited signifie que si vous utilisez des proxies basés sur des classes, les paramètres de transaction ne seront pas reconnus par l'infrastructure de proxy basée sur des classes et l'objet ne sera pas enveloppé dans un proxy transactionnel (ce qui serait décidément mauvais ). Veuillez donc suivre les conseils de L'équipe Spring et annoter uniquement les classes concrètes (et les méthodes des classes concrètes) avec l'annotation @Transactional.

Note: puisque ce mécanisme est basé sur des proxies, seule la méthode' externe' les appels entrant via le proxy seront interceptés. cela signifie que 'self-invocation', c'est-à-dire une méthode dans l'objet cible appelant une autre méthode de l'objet cible, ne conduira pas à une transaction réelle au moment de l'exécution même si la méthode invoquée est marquée avec @Transactional!

(soulignement ajouté à la première phrase, autres soulignements de l'original.)

92
répondu Romain Hippeau 2010-06-26 06:24:33

Vous pouvez les mettre sur l'interface mais être averti que les transactions peuvent ne pas finir par se produire dans certains cas. Voir la deuxième astuce dans Secion 10.5.6 des documents Spring:

Spring recommande d'annoter uniquement les classes concrètes (et les méthodes des classes concrètes) avec l'annotation @ Transactional, par opposition aux interfaces d'Annotation. Vous pouvez certainement placer l'annotation @Transactional sur une interface (ou une méthode d'interface), mais cela ne fonctionne que comme prévu si vous utilisez des proxys basés sur l'interface. Le fait que les annotations Java ne soient pas héritées des interfaces signifie que si vous utilisez des proxys basés sur des classes (proxy-target-class="true") ou l'aspect basé sur le tissage (mode="aspectj"), les paramètres de transaction ne sont pas reconnus par l'infrastructure de proxy et de tissage, et l'objet ne sera pas enveloppé dans un proxy transactionnel,

Je recommande de les mettre sur l'implémentation pour cela raison.

En outre, pour moi, les transactions semblent être un détail d'implémentation, elles devraient donc être dans la classe d'implémentation. Imaginez avoir des implémentations wrapper pour la journalisation ou les implémentations de test (mocks) qui n'ont pas besoin d'être transactionnelles.

8
répondu AngerClown 2010-06-25 18:06:20

La recommandation de Spring {[3] } est que vous annotez les implémentations concrètes au lieu d'une interface. Il n'est pas incorrect d'utiliser l'annotation sur une interface, il est juste possible d'abuser de cette fonctionnalité et de contourner par inadvertance votre déclaration @Transaction.

Si vous avez marqué quelque chose de transactionnel dans une interface et que vous vous référez à l'une de ses classes d'implémentation ailleurs dans spring, il n'est pas tout à fait évident que l'objet créé par spring ne respectera pas le @ Annotation transactionnelle.

En pratique, cela ressemble à ceci:

public class MyClass implements MyInterface { 

    private int x;

    public void doSomethingNonTx() {}

    @Transactional
    public void toSomethingTx() {}

}
6
répondu zmf 2010-06-25 18:12:19

Prise en charge de @Transactional sur les classes concrètes:

Je préfère concevoir une solution en 3 sections en général: une API, une implémentation et un Web (si nécessaire). Je fais de mon mieux pour garder L'API aussi légère/simple/POJO que possible en minimisant les dépendances. C'est particulièrement important si vous le jouez dans un environnement distribué/intégré où vous devez partager beaucoup les API.

Mettre @Transactional nécessite des bibliothèques Spring dans la section API, CE QUI à mon humble avis n'est pas efficace. Je préfère donc l'ajouter dans l'implémentation où la transaction est en cours d'exécution.

1
répondu Firdous Amir 2015-03-28 16:43:05

Le mettre sur l'interface est bien tant que tous les implémenteurs prévisibles de votre IFC se soucient des données TX (les transactions ne sont pas des problèmes que les bases de données traitent). Si la méthode ne se soucie pas de TX (mais vous devez le mettre là pour Hibernate ou autre), mettez - le sur l'impl.

En outre, il pourrait être un peu préférable de placer @Transactional sur les méthodes de l'interface:

public interface FooService {
    @Transactional(readOnly = true)
    void doSmth();
}
0
répondu engfer 2010-06-25 17:53:30

Veuillez jeter un oeil au lien ci-dessous qui illustre le problème avec un exemple simple mais expliquant:

Http://kim.saabye-pedersen.org/2013/05/spring-annotation-on-interface-or-class.html

0
répondu user2353505 2013-05-06 05:36:03