代码中标题的问题:
@Transactional (readonly = true)
public interface FooService {
void doSmth ();
}
public class FooServiceImpl implements FooService {
...
}
对
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 团队的建议是只使用
注解来注解具体类,而不是注解接口。 你当然可以将@Transactional
注解放在接口(或接口方法)上,但这只会如果您使用基于接口的代理,它会按照您期望的方式工作。注释“不是继承的”这一事实意味着,如果您使用基于类的代理,那么基于类的代理基础设施将无法识别事务设置,并且对象将不会被包装在事务代理中(这显然是坏)。因此,请务必采纳 Spring 团队的建议,仅使用@Transactional
@Transactional
注释来注释具体类(以及具体类的方法)。注意:由于此机制基于代理,因此只有通过代理传入的“外部”方法调用才会被拦截。这意味着“自调用”,即目标对象中的方法调用对象的其他方法目标对象,即使调用的方法标有
@Transactional
!,也不会在运行时导致实际事务(强调添加到第一句,其他强调来自原文。)
是注释具体的实现而不是接口。在接口上使用注释并不是不正确,只是有可能滥用该功能并无意中绕过您的 @Transaction 声明。 如果您在接口中标记了某些事务性内容,然后在 spring 中的其他地方引用其实现类之一,则 spring 创建的对象不会遵守 @Transactional 注释,这一点并不十分明显。
实际上,它看起来像这样:
public class MyClass implements MyInterface {
private int x;
public void doSomethingNonTx() {}
@Transactional
public void toSomethingTx() {}
}
出于这个原因,我建议将它们付诸实施。另外,对我来说,事务似乎是一个实现细节,因此它们应该位于实现类中。想象一下,拥有不需要事务性的日志记录或测试实现(模拟)的包装器实现。
在具体类上支持@Transactional:
放置 @Transactional 需要 API 部分中的 Spring 库,恕我直言,这并不有效。所以我更喜欢将其添加到运行事务的实现中。
只要 IFC 的所有可预见的实施者都关心 TX 数据(交易不是数据库处理的问题),将其放在接口上就可以了。如果该方法不关心 TX(但您需要将其放在那里以用于 Hibernate 或其他),请将其放在 impl 上。
@Transactional
放在界面中的方法上可能会更好一点:
public interface FooService {
@Transactional(readOnly = true)
void doSmth();
}