De http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
La recommandation de l'équipe Spring est que vous n'annotiez que les classes concrètes avec l' @Transactional
annotation, par opposition aux interfaces d'annotation. Vous pouvez certainement placer l' @Transactional
annotation sur une interface (ou une méthode d'interface), mais cela ne fonctionnera que comme vous vous y attendez si vous utilisez des proxys basés sur l'interface. Le fait que les annotations ne soient pas héritées signifie que si vous utilisez des proxys basés sur les classes, les paramètres de transaction ne seront pas reconnus par l'infrastructure de proxy basée sur les classes et l'objet ne sera pas enveloppé dans un proxy transactionnel (ce qui serait décidément mauvais ) . Alors s'il vous plaît, suivez les conseils de l'équipe Spring et n'annotez que les classes concrètes (et les méthodes des classes concrètes) avec l' @Transactional
annotation.
Remarque: puisque ce mécanisme est basé sur des proxies, seuls les appels de méthode «externes» arrivant via le proxy seront interceptés. Cela signifie que «l'auto-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 à l'exécution même si la méthode invoquée est marquée @Transactional
!
(Emphase ajoutée à la première phrase, autre emphase de l'original.)
JdkDynamicAopProxy
tous les conseillers de bean passent par chaque appel de méthode (voir aussiDefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice()
), ce qui inclut dans le cas d'une configuration de transaction déclarativeBeanFactoryTransactionAttributeSourceAdvisor
. A son tourTransactionAttributeSourcePointcut#matches()
est invoqué, qui devrait collecter les informations relatives à la transaction. Il reçoit la classe cible et peut toujours traverser toutes les interfaces implémentées par cette classe. Maintenant: pourquoi cela ne peut pas fonctionner de manière fiable?@Transactional
annotations héritées s'appliquerait? Donc, bien que tout soit possible , je ne blâme pas Spring. jira.springsource.org/browse/SPR-975Vous pouvez les mettre sur l'interface, mais sachez que les transactions peuvent ne pas se produire dans certains cas. Voir le deuxième conseil dans la section 10.5.6 de la documentation Spring:
Je recommanderais de les mettre sur la mise en œuvre pour cette raison.
De plus, pour moi, les transactions semblent être un détail d'implémentation et doivent donc être dans la classe d'implémentation. Imaginez avoir des implémentations wrapper pour la journalisation ou des implémentations de test (mocks) qui n'ont pas besoin d'être transactionnelles.
la source
La recommandation de Spring est d'annoter les implémentations concrètes au lieu d'une interface. Il n'est pas incorrect d'utiliser l'annotation sur une interface, il est simplement possible de mal utiliser 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 ensuite à l'une de ses classes d'implémentation ailleurs au printemps, il n'est pas tout à fait évident que l'objet créé par spring ne respectera pas l'annotation @Transactional.
En pratique, cela ressemble à ceci:
public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} }
la source
Soutenir @Transactional sur les classes concrètes:
Je préfère concevoir une solution en 3 sections généralement: une API, une Implémentation et un Web (si besoin). 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 y jouez dans un environnement distribué / intégré où vous devez beaucoup partager 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 s'exécute.
la source
Le mettre sur l'interface est très 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 seules les bases de données traitent). Si la méthode ne se soucie pas de TX (mais que vous devez la mettre là pour Hibernate ou autre), mettez-la sur 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(); }
la source