我应该在哪里放置@Transactional注解:在接口定义还是在实现类?

来自代码标题的问题:

@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 { ... } 

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

Spring团队的build议是,您只能使用@Transactional注释来注释具体的类,而不是注释接口。 您当然可以将@Transactional注释放置在一个接口(或一个接口方法)上,但是这只会在您使用基于接口的代理的情况下正常工作。 注释不被inheritance的事实意味着,如果您使用的是基于类的代理,那么事务设置将不会被基于类的代理基础架构所识别,并且该对象将不会被包装在事务代理中(这肯定会很糟糕 ) 。 所以,请务必采纳Spring团队的build议,只用@Transactional注释来注释具体类(以及具体类的方法)。

注意:由于这个机制是基于代理的,所以只有通过代理进入的“外部”方法调用才会被拦截。 这意味着即使被调用的方法标记为@Transactional ,“自调用”(即调用目标对象的其他方法的目标对象内的方法)也不会导致实际的事务处理。

(第一句强调加重,另外强调原文。)

你可以把它们放在界面上,但要注意在某些情况下交易可能不会发生。 请参阅Spring文档Secion 10.5.6中的第二个提示:

Springbuild议您只使用@Transactional注释来注释具体类(以及具体类的方法),而不是注释接口。 您当然可以将@Transactional注释放在一个接口(或一个接口方法)上,但是这只能在您使用基于接口的代理的情况下使用。 Java注释没有从接口inheritance的事实意味着,如果您使用的是基于类的代理(proxy-target-class =“true”)或基于交织的方面(mode =“aspectj”),那么交易设置是没有被代理和编织基础架构认可,并且该对象不会被封装在一个事务代理中,这将是非常糟糕的。

为了这个原因,我build议把它们放在实现上。

而且,对我来说,事务看起来像是一个实现细节,所以他们应该在实现类中。 想象一下,为了logging或testing实现(嘲笑),不需要事务性的包装实现。

Spring的build议是你注释具体的实现,而不是一个接口。 在界面上使用注释并不正确,只是可能会误用该function而无意中绕过@Transaction声明。

如果你已经在接口中标记了事务,然后在Spring的其他地方引用它的一个实现类,那么Spring创build的对象将不会尊重@Transactional注释。

在实践中,它看起来像这样:

 public class MyClass implements MyInterface { private int x; public void doSomethingNonTx() {} @Transactional public void toSomethingTx() {} } 

把它放在界面上就好像所有可预见的IFC关心TX数据的实现者一样(交易不是只有数据库处理的问题)。 如果该方法不关心TX(但是你需要把它放在Hibernate或者其他地方),把它放在impl上。

此外,将@Transactional放在界面中的方法上可能会更好一些:

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

请看下面的链接,通过一个简单的例子说明问题:

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

支持@Transactional对具体的类:

我更喜欢通常在三个部分构build解决scheme:一个API,一个实现和一个Web(如果需要)。 尽我所能通过最小化依赖关系来尽可能地将API保持为l​​ight / simple / POJO。 如果您在分布式/集成环境中播放,您必须大量共享API,这一点尤其重要。

把@Transactional需要在API部分,恕我直言,是不是有效的spring图书馆。 所以我更喜欢将它添加到事务正在运行的实现中。