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

2022-08-31 10:34:53

代码中标题中的问题:

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

答案 1

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

Spring团队的建议是,你只用@Transactional注释来注释具体的类,而不是注释接口。您当然可以将注释放在接口(或接口方法)上,但这只有在使用基于接口的代理时才能按预期工作。注释不被继承的事实意味着,如果您使用的是基于类的代理,那么基于类的代理基础结构将无法识别事务设置,并且对象将不会包装在事务代理中(这绝对是糟糕的)。因此,请接受Spring团队的建议,只用注释来注释具体的类(以及具体类的方法)。@Transactional@Transactional

注意:由于此机制基于代理,因此只有通过代理传入的“外部”方法调用才会被拦截。这意味着“自调用”,即目标对象内的方法调用目标对象的其他方法,即使调用的方法标记为 !@Transactional

(强调部分加到第一句,其他强调部分来自原文。


答案 2

Spring的建议是,你注释具体的实现而不是接口。在接口上使用注释并不是不正确的,只是可能滥用该功能并无意中绕过@Transaction声明。

如果你在一个接口中标记了一些事务性的东西,然后在春天的其他地方引用了它的一个实现类,那么spring创建的对象不会尊重@Transactional注释,这一点并不明显。

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

public class MyClass implements MyInterface { 

    private int x;

    public void doSomethingNonTx() {}

    @Transactional
    public void toSomethingTx() {}

}