// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}
Spring 天的一个新兴趋势是朝着domain-driven design(DDD) . Spring Roo很好地举例说明了这一趋势 . 我们的想法是使域对象POJO比典型的Spring架构(通常它们是anemic)要多得多,特别是将事务和持久性语义放在域对象本身上 . 如果所有's needed is simple CRUD operations, the web controllers operate directly on the domain object POJOs (they'在此上下文中作为实体运行,并且域对象之间需要某种协调,则可以使用 @Transaction 按照传统使用服务bean句柄 . 您可以将域对象上的事务传播设置为类似 REQUIRED 的内容,以便域对象使用任何现有事务,例如在服务bean上启动的事务 .
Or does it make sense to annotate both "layers"? - 注释服务层和dao层是否有意义 - 如果想要确保始终从DAO中具有传播"mandatory"的服务层调用(传播)DAO方法 . 这将为从UI层(或控制器)调用DAO方法提供一些限制 . 此外 - 当特别是对DAO层进行单元测试时 - 对DAO进行注释也将确保对其进行交易功能测试 .
//Without @Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//After getting Country Object connection between countryRepository and database is Closed
}
当我们想要从country对象访问City of Cities时,我们将在该Set中获取null值,因为Set的对象只创建了这个Set没有初始化那里有数据来获取Set的值我们使用 @Transactional 即,
//with @Transactional
@Transactional
public Country getCountry(){
Country country = countryRepository.getCountry();
//below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
Object object = country.getCities().size();
}
19 回答
理想情况下,服务层(Manager)代表您的业务逻辑,因此应使用_635448注释.Service层可以调用不同的DAO来执行数据库操作 . 让我们假设您在服务方法中有N个DAO操作的情况 . 如果您的第一个DAO操作失败,其他人可能仍然通过,您将最终导致不一致的DB状态 . 注释服务层可以帮助您避免这种情况 .
我更喜欢在方法级别的服务层上使用
@Transactional
.@Transactional
在服务层中使用,该服务层通过使用控制器层(@Controller
)和服务层调用DAO层(@Repository
)来调用,即数据库相关操作 .@Transactional
应该在服务层上使用,因为它包含业务逻辑 . DAO层通常只有数据库CRUD操作 .Spring doc:https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html
我认为交易属于服务层 . 它是了解工作单元和用例的人 . 如果您将几个DAO注入到需要在单个事务中协同工作的服务中,那么这是正确的答案 .
一般而言,我同意其他人的观点,即交易通常是在服务级别上启动的(取决于您当然需要的粒度) .
但是,与此同时,我也开始将
@Transactional(propagation = Propagation.MANDATORY)
添加到我的DAO层(以及其他不允许启动事务但需要现有事务的层),因为在忘记在调用者中启动事务时,更容易检测错误(例如服务) . 如果您的DAO使用强制传播进行注释,则会收到一个异常,指出在调用该方法时没有活动事务 .我还有一个集成测试,其中我检查所有bean(bean post processor)以获取此注释,如果在不属于服务层的bean中存在除了Mandatory之外的传播的
@Transactional
注释,则会失败 . 这样我确保我们不会在错误的层上启动事务 .Transactional Annotations应围绕所有不可分割的操作 .
例如,您的电话是“更改密码” . 这包括两个操作
更改密码 .
审核变更 .
通过电子邮件向客户端发送密码已更改 .
所以在上面,如果审核失败,那么密码更改是否也会失败?如果是这样,那么交易应该在1和2左右(所以在服务层) . 如果电子邮件失败(可能应该具有某种故障安全性,因此它不会失败)那么它应该回滚更改密码和审核吗?
这些是你在决定把
@Transactional
放在哪里时需要问的问题 .通常的情况是在服务层级别上进行注释,但这实际上取决于您的要求 .
在服务层上添加注释将导致比DAO级别上的注释更长的事务 . 取决于可以解决问题的事务隔离级别,因为并发事务不会看到彼此的更改,例如 . 可重复阅读 .
对DAO进行注释将使事务保持尽可能短,缺点是服务层公开的功能不会在单个(可回滚)事务中完成 .
如果传播模式设置为默认值,则注释两个图层没有意义 .
传统Spring体系结构的正确答案是在服务类上放置事务语义,这是其他人已经描述过的原因 .
Spring 天的一个新兴趋势是朝着domain-driven design(DDD) . Spring Roo很好地举例说明了这一趋势 . 我们的想法是使域对象POJO比典型的Spring架构(通常它们是anemic)要多得多,特别是将事务和持久性语义放在域对象本身上 . 如果所有's needed is simple CRUD operations, the web controllers operate directly on the domain object POJOs (they'在此上下文中作为实体运行,并且域对象之间需要某种协调,则可以使用
@Transaction
按照传统使用服务bean句柄 . 您可以将域对象上的事务传播设置为类似REQUIRED
的内容,以便域对象使用任何现有事务,例如在服务bean上启动的事务 .从技术上讲,这种技术使用了AspectJ和
<context:spring-configured />
. Roo使用AspectJ交互式定义将实体语义(事务和持久性)与域对象(基本上是字段和业务方法)分开 .我将
@Transactional
放在@Service
图层上并设置rollbackFor
任何异常和readOnly
以进一步优化事务 .默认情况下
@Transactional
将仅查找RuntimeException
(未经检查的异常),通过将回滚设置为Exception.class
(已检查的异常),它将回滚任何异常 .见Checked vs. Unchecked Exceptions .
Or does it make sense to annotate both "layers"? - 注释服务层和dao层是否有意义 - 如果想要确保始终从DAO中具有传播"mandatory"的服务层调用(传播)DAO方法 . 这将为从UI层(或控制器)调用DAO方法提供一些限制 . 此外 - 当特别是对DAO层进行单元测试时 - 对DAO进行注释也将确保对其进行交易功能测试 .
另外,Spring建议仅在具体类而不是接口上使用注释 .
http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
对于数据库级别的事务
大多数时候我在DAO的方法中使用了
@Transactional
级别,所以配置可以专门用于方法/使用默认值(必需)DAO 's method that get data fetch (select .. ) - don' t需要
@Transactional
这可能会导致一些开销,因为事务拦截器/和AOP代理也需要执行 .DAO的插入/更新方法将获得
@Transactional
非常好的博客transctional
对于申请级别 -
我正在使用事务性的业务逻辑我希望能够在出现意外错误时回滚
通常,应该在服务层放置一个事务 .
但如前所述,操作的原子性告诉我们注释在哪里是必要的 . 因此,如果您使用像Hibernate这样的框架,其中对对象的单个“保存/更新/删除/修改”操作可能会修改多个表中的多个行(因为通过对象图层级联),当然还应该对这种特定的DAO方法进行事务管理 .
最好将它放在服务层中!昨天我遇到的一篇文章清楚地解释了这一点!这是the link,你可以看看!
@Transactional
应在所有不可分割的操作周围放置注释 . 使用@Transactional
事务传播是自动处理的 . 在这种情况下,如果当前方法调用另一个方法,那么该方法将具有加入正在进行的事务的选项 .让我们举个例子:
我们有2个模型,即
Country
和City
.Country
和City
模型的关系映射就像一个Country
可以有多个城市所以映射就像,这里国家映射到多个城市,并提取它们
Lazily
. 因此,当我们从数据库中检索Country对象时,我们将获得@Transactinal
的角色,然后我们将获得Country对象的所有数据但不会获得城市集,因为我们正在获取城市LAZILY
.当我们想要从country对象访问City of Cities时,我们将在该Set中获取null值,因为Set的对象只创建了这个Set没有初始化那里有数据来获取Set的值我们使用
@Transactional
即,所以基本上
@Transactional
是服务可以在单个事务中进行多次调用而不关闭与 endpoints 的连接 .首先让我们定义我们必须使用 transaction 的位置?
我认为正确答案是 - 当我们需要确保将一系列操作作为一个原子操作完成时,或者即使其中一个操作失败也不会进行任何更改 .
众所周知,将业务逻辑放入服务中 . 因此,服务方法可能包含必须作为单个逻辑工作单元执行的不同操作 . 如果是这样 - 那么这种方法必须标记为 Transactional . 当然,并非每种方法都需要这样的限制,因此您不需要将整个服务标记为事务性的 .
甚至更多 - 不要忘记考虑到 @Transactional 显然,可能会降低方法性能 . 为了查看整个图片,您必须知道事务隔离级别 . 知道这可能会帮助您避免在不一定需要的地方使用@Transactional .
服务层是添加
@Transactional
注释作为此处存在的大多数业务逻辑的最佳位置,它包含详细级别的用例行为 .假设我们将它添加到DAO,并且从服务我们调用2个DAO类,一个失败并且其他成功,在这种情况下,如果
@Transactional
不在服务上,则一个DB将提交而其他将回滚 .因此,我的建议是明智地使用此注释,并仅在服务层使用 .
Github project- java-algos
最好将 @Transactional 保存在DAO和服务层之间的单独中间层中 . 由于回滚非常重要,您可以将所有数据库操作放在中间层,并在服务层中编写业务逻辑 . 中间层将与您的DAO层交互 .
这将在许多情况下帮助您,例如 ObjectOptimisticLockingFailureException - 只有在您的交易结束后才会发生此异常 . 所以,你不能在中间层捕获它,但你现在可以捕获你的服务层 . 这个会如果你在服务层有@Transactional,则无法实现 . 虽然你可以捕获控制器,但控制器应该尽可能干净 .
如果您在完成所有保存,删除和更新选项后以单独的线程发送邮件或短信,则可以在中间层完成交易后在服务中执行此操作 . 同样,如果您在服务层中提及@Transactional,即使您的交易失败,您也会收到邮件 .
因此,拥有一个中间@Transaction层将有助于使您的代码更好,更容易处理 . 否则,如果在DAO层中使用,则可能无法回滚所有操作 . 如果在Service层中使用,则在某些情况下可能必须使用 AOP (面向方面编程) .