Java 我应该把 @Transactional 注释放在哪里:在接口定义还是在实现类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3120143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Where should I put @Transactional annotation: at an interface definition or at an implementing class?
提问by Roman
The question from the title in 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 {
...
}
采纳答案by Romain Hippeau
From http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
来自http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
The Spring team's recommendation is that you only annotate concrete classes with the
@Transactional
annotation, as opposed to annotating interfaces.You certainly can place the@Transactional
annotation on an interface (or an interface method), but this will only work as you would expect it to if you are using interface-based proxies. The fact that annotations are not inheritedmeans that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy (which would be decidedly bad). So please do take the Spring team's advice and only annotate concrete classes (and the methods of concrete classes) with the@Transactional
annotation.Note: Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted.This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with
@Transactional
!
Spring 团队的建议是您只使用注释来注释具体的类
@Transactional
,而不是注释接口。您当然可以将@Transactional
注解放在接口(或接口方法)上,但是如果您使用基于接口的代理,这只会像您期望的那样工作。注释未被继承这一事实意味着,如果您使用基于类的代理,那么基于类的代理基础结构将无法识别事务设置,并且对象将不会被包装在事务代理中(这绝对是不好的) . 因此,请务必接受 Spring 团队的建议,并仅使用注释来注释具体类(以及具体类的方法)@Transactional
。注意:由于此机制基于代理,因此只会拦截通过代理传入的“外部”方法调用。这意味着“自调用”,即目标对象中的方法调用目标对象的其他方法,即使被调用的方法被标记为
@Transactional
!也不会在运行时导致实际事务。
(Emphasis added to the first sentence, other emphasis from the original.)
(强调添加到第一句,其他强调来自原文。)
回答by engfer
Putting it on the interface is fine as long all foreseeable implementers of your IFC care about TX data (transactions aren't problems that just databases deal with). If the method doesn't care about TX (but you need to put it there for Hibernate or whatever), put it on the impl.
只要您的 IFC 的所有可预见的实现者都关心 TX 数据(事务不仅仅是数据库处理的问题),将它放在界面上就可以了。如果该方法不关心 TX(但您需要将它放在 Hibernate 或其他任何地方),请将其放在 impl 上。
Also, it might be a bit better to place @Transactional
on the methods in the interface:
此外,@Transactional
将方法放在接口中可能会更好一些:
public interface FooService {
@Transactional(readOnly = true)
void doSmth();
}
回答by AngerClown
You can put them on the interface but be warn that transactions may not end up happening in some cases. See the second tip in Secion 10.5.6of the Spring docs:
您可以将它们放在界面上,但要注意在某些情况下交易可能不会最终发生。请参阅Spring 文档第10.5.6 节中的第二个提示:
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.
Spring 建议您只使用 @Transactional 注释来注释具体类(和具体类的方法),而不是注释接口。您当然可以将 @Transactional 注释放在接口(或接口方法)上,但是如果您使用基于接口的代理,这只能像您期望的那样工作。Java 注释不是从接口继承的事实意味着如果您使用基于类的代理 (proxy-target-class="true") 或基于编织的方面 (mode="aspectj"),那么事务设置是不被代理和编织基础设施识别,并且对象不会被包装在事务代理中,这绝对是糟糕的。
I would recommend putting them on the implementation for this reason.
出于这个原因,我建议将它们放在实施中。
Also, to me, transactions seem like an implementation detail so they should be in the implementation class. Imagine having wrapper implementations for logging or test implementations (mocks) that don't need to be transactional.
另外,对我来说,事务似乎是一个实现细节,所以它们应该在实现类中。想象一下,有用于不需要事务性的日志记录或测试实现(模拟)的包装器实现。
回答by zmf
Spring's recommendationis that you annotate the concrete implementations instead of an interface. It's not incorrect to use the annotation on an interface, it's just possible to misuse that feature and inadvertently bypass your @Transaction declaration.
Spring 的建议是您注释具体实现而不是接口。在接口上使用注解并没有错,只是可能会误用该功能并无意中绕过您的 @Transaction 声明。
If you've marked something transactional in an interface and then refer to one of its implementing classes elsewhere in spring, it's not quite obvious that the object that spring creates will not respect the @Transactional annotation.
如果您在接口中标记了一些事务性的东西,然后在 spring 的其他地方引用它的一个实现类,那么 spring 创建的对象不会尊重 @Transactional 注释就不是很明显了。
In practice it looks something like this:
在实践中它看起来像这样:
public class MyClass implements MyInterface {
private int x;
public void doSomethingNonTx() {}
@Transactional
public void toSomethingTx() {}
}
回答by Firdous Amir
Supporting @Transactional on the concrete classes:
在具体类上支持@Transactional:
I prefer to architect a solution in 3 sections generally: an API, an Implementation and a Web (if needed). I try my best to keep the API as light/simple/POJO as possible by minimizing dependencies. It's especially important if you play it in a distributed/integrated environment where you have to share the APIs a lot.
我更喜欢在 3 个部分中构建解决方案:API、实现和 Web(如果需要)。我尽量通过最小化依赖来保持 API 尽可能轻巧/简单/POJO。如果您在必须大量共享 API 的分布式/集成环境中使用它,这一点尤其重要。
Putting @Transactional requires Spring libraries in the API section, which IMHO is not effective. So I prefer to add it in the Implementation where the transaction is running.
将@Transactional 放在 API 部分需要 Spring 库,恕我直言无效。所以我更喜欢在事务运行的实现中添加它。