Java @Transactional 注释属于哪里?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1079114/
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 does the @Transactional annotation belong?
提问by Thomas Einwaller
Should you place the @Transactional
in the DAO
classes and/or their methods or is it better to annotate the Service classes which are calling using the DAO objects? Or does it make sense to annotate both "layers"?
如果您将@Transactional
在DAO
类和/或它们的方法还是更愿意到签注使用DAO对象调用服务类?或者注释两个“层”是否有意义?
采纳答案by duffymo
I think transactions belong on the Service layer. It's the one that knows about units of work and use cases. It's the right answer if you have several DAOs injected into a Service that need to work together in a single transaction.
我认为事务属于服务层。它是了解工作单元和用例的人。如果您将多个 DAO 注入到需要在单个事务中协同工作的服务中,那么这是正确的答案。
回答by hammarback
The normal case would be to annotate on a service layer level, but this really depends on your requirements.
正常情况是在服务层级别进行注释,但这实际上取决于您的要求。
Annotating on a service layer will result in longer transactions than annotating on DAO level. Depending on the transaction isolation level that can youse problems, as concurrent transactions wont see each other's changes in eg. REPEATABLE READ.
与在 DAO 级别上注释相比,在服务层上进行注释将导致更长的事务。取决于可以解决问题的事务隔离级别,因为并发事务不会看到彼此的更改,例如。可重复阅读。
Annotating on the DAOs will keep the transactions as short as possible, with the drawback that the functionality your service layer is exposing wont be done in a single (rollbackable) transaction.
在 DAO 上注释将使事务尽可能短,缺点是您的服务层公开的功能不会在单个(可回滚)事务中完成。
It does not make sense to annotate both layers if the propagation mode is set to default.
如果传播模式设置为默认,则对两个层都进行注释是没有意义的。
回答by Michael Wiles
Transactional Annotations should be placed around all operations that are inseparable.
事务注释应该放在所有不可分割的操作周围。
For example, your call is "change password". That consists of two operations
例如,您的呼叫是“更改密码”。这包括两个操作
- Change the password.
- Audit the change.
- Email the client that the password has changed.
- 更改密码。
- 审核更改。
- 向客户端发送电子邮件,告知密码已更改。
So in the above, if the audit fails, then should the password change also fail? If so, then the transaction should be around 1 and 2 (so at the service layer). If the email fails (probably should have some kind of fail safe on this so it won't fail) then should it roll back the change password and the audit?
那么在上面,如果审计失败,那么密码更改是否也会失败?如果是这样,那么事务应该在 1 和 2 左右(所以在服务层)。如果电子邮件失败(可能应该有某种故障安全,所以它不会失败)那么它是否应该回滚更改密码和审计?
These are the kind of questions you need to be asking when deciding where to put the @Transactional
.
这些是您在决定将@Transactional
.
回答by davidemm
Also, Spring recommends only using the annotation on concrete classes and not interfaces.
此外,Spring 建议只在具体类而不是接口上使用注解。
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
回答by sundary
回答by sundary
The correct answer for traditional Spring architectures is to place transactional semantics on the service classes, for the reasons that others have already described.
传统 Spring 架构的正确答案是将事务语义放在服务类上,其原因其他人已经描述过。
An emerging trend in Spring is toward domain-driven design(DDD). Spring Rooexemplifies the trend nicely. The idea is to make the domain object POJOs a lot richerthan they are on typical Spring architectures (usually they are anemic), and in particular to put transaction and persistence semantics on the domain objects themselves. In cases where all that's needed is simple CRUD operations, the web controllers operate directly on the domain object POJOs (they're functioning as entities in this context), and there's no service tier. In cases where there's some kind of coordination needed between domain objects, you can have a service bean handle that, with @Transaction
as per tradition. You can set the transaction propagation on the domain objects to something like REQUIRED
so that the domain objects use any existing transactions, such as transactions that were started at the service bean.
Spring 的一个新兴趋势是领域驱动设计(DDD)。Spring Roo很好地体现了这一趋势。这个想法是使域对象 POJO比典型的 Spring 架构(通常它们是贫血的)更丰富,特别是将事务和持久性语义放在域对象本身上。在所有需要的只是简单的 CRUD 操作的情况下,Web 控制器直接在域对象 POJO 上操作(它们在此上下文中作为实体运行),并且没有服务层。在域对象之间需要某种协调的情况下,您可以使用一个服务 bean 来处理它,@Transaction
按照传统。您可以将域对象上的事务传播设置为类似的内容,REQUIRED
以便域对象使用任何现有事务,例如在服务 bean 上启动的事务。
Technically this technique makes use of AspectJ and <context:spring-configured />
. Roo uses AspectJ inter-type definitions to separate the entity semantics (transactions and persistence) from the domain object stuff (basically fields and business methods).
从技术上讲,这种技术利用了 AspectJ 和<context:spring-configured />
. Roo 使用 AspectJ 类型间定义将实体语义(事务和持久性)与域对象内容(基本上是字段和业务方法)分开。
回答by yannick555
Usually, one should put a transaction at the service layer.
通常,应该将事务放在服务层。
But as stated before, the atomicity of an operation is what tells us where an annotation is necessary. Thus, if you use frameworks like Hibernate, where a single "save/update/delete/...modification" operation on an object has the potential to modify several rows in several tables (because of the cascade through the object graph), of course there should also be transaction management on this specific DAO method.
但如前所述,操作的原子性告诉我们哪里需要注解。因此,如果您使用像 Hibernate 这样的框架,其中一个对象上的单个“保存/更新/删除/...修改”操作有可能修改多个表中的几行(因为通过对象图的级联),当然,这个特定的 DAO 方法也应该有事务管理。
回答by tweekran
Or does it make sense to annotate both "layers"?- doesn't it make sense to annotate both the service layer and the dao layer - if one wants to make sure that DAO method is always called (propagated) from a service layer with propagation "mandatory" in DAO. This would provide some restriction for DAO methods from being called from UI layer (or controllers). Also - when unit testing DAO layer in particular - having DAO annotated will also ensure it is tested for transactional functionality.
或者注释两个“层”是否有意义?- 对服务层和 dao 层都进行注释是否有意义 - 如果要确保始终从在 DAO 中传播“强制”的服务层调用(传播)DAO 方法。这将为从 UI 层(或控制器)调用 DAO 方法提供一些限制。此外 - 特别是在单元测试 DAO 层时 - 对 DAO 进行注释也将确保它针对事务功能进行测试。
回答by mnp
In general I agree with the others stating that transactions are usually started on the service level (depending on the granularity that you require of course).
总的来说,我同意其他人所说的事务通常在服务级别开始(当然取决于您需要的粒度)。
However, in the mean time I also started adding @Transactional(propagation = Propagation.MANDATORY)
to my DAO layer (and other layers that are not allowed to start transactions but require existing ones) because it is much easier to detect errors where you have forgotten to start a transaction in the caller (e.g. the service). If your DAO is annotated with mandatory propagation you will get an exception stating that there is no active transaction when the method is invoked.
然而,与此同时,我也开始添加@Transactional(propagation = Propagation.MANDATORY)
到我的 DAO 层(以及其他不允许启动事务但需要现有事务的层),因为在您忘记在调用者中启动事务的地方更容易检测错误(例如服务)。如果您的 DAO 使用强制传播进行注释,您将收到一个异常,指出调用该方法时没有活动事务。
I also have an integration test where I check all beans (bean post processor) for this annotation and fail if there is a @Transactional
annotation with propagation other than Mandatory in a bean that does not belong to the services layer. This way I make sure we do not start transactions on the wrong layer.
我还有一个集成测试,我检查此注释的所有 bean(bean 后处理器),如果@Transactional
在不属于服务层的 bean 中存在除 Mandatory 之外的传播的注释,则失败。这样我可以确保我们不会在错误的层上开始交易。
回答by lukass77
For Transaction in database level
对于数据库级别的事务
mostly I used @Transactional
in DAO's just on method level, so configuration can be specifically for a method / using default (required)
我主要@Transactional
在 DAO 中仅在方法级别使用,因此配置可以专门用于方法/使用默认值(必需)
DAO's method that get data fetch (select .. ) - don't need
@Transactional
this can lead to some overhead because of transaction interceptor / and AOP proxy that need to be executed as well.DAO's methods that do insert / update will get
@Transactional
DAO 的获取数据的方法 (select .. ) - 不需要
@Transactional
这会导致一些开销,因为事务拦截器/和 AOP 代理也需要执行。DAO 的插入/更新方法将得到
@Transactional
very good blog on transctional
关于transctional 的非常好的博客
For application level -
I am using transactional for business logic I would like to be able rolback in case of unexpected error
对于应用程序级别 -
我将事务性用于业务逻辑,我希望能够在出现意外错误时回滚
@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){
try {
//service logic here
} catch(Throwable e) {
log.error(e)
throw new MyApplicationException(..);
}
}