我阅读了一些关于如何设置事务以将 Spring 和 Hibernate 连接在一起的内容。看起来推荐的方法是在服务层初始化事务。
当然。事务划分应该在服务层级别进行,而不是在 DAO 层级别:
- 工作单元是服务,而不是 DAO
- 如果需要,您希望事务跨越多个 DAO。
我不喜欢的是大多数事务的存在只是因为它们是休眠正常工作所必需的。
您也许应该详细说明这部分,因为事务不是 Hibernate 特定的。
当我真的需要一个事务来调用多个服务方法的作业时,似乎我没有选择继续从作业初始化事务。
如果您想在从 Job 层启动的事务中调用多个服务,请使用 REQUIRED 语义(默认)将您的服务声明为事务性并依赖 Spring 事务传播(除非您需要远程调用,否则这适用;在在这种情况下,请使用 EJB)。
因此,将 @Transactional 注释从 DAO 移动到服务似乎没有任何区别。
它确实会有所不同,并且在运行批处理时需要从作业层启动事务这一事实并没有使事情有所不同。
强烈推荐阅读Chapter 9. Transaction management。
(...) 我的主要问题来自 Hibernate。对不起,如果我不清楚。
没问题。只是当一个问题含糊不清时,你往往得到一个含糊的答案:)
来自休眠文档:“数据库事务永远不是可选的。与数据库的所有通信都必须发生在事务内部。”。这就是为什么开发人员将 DAO 方法放在我的项目中的原因。
抱歉,上面的语句只是说“与数据库的通信必须发生在内部事务”,仅此而已,剩下的就是决定从哪里开始事务由您自行决定(通常是服务层)。如果在 DAO 级别进行,如果 MySuperService 调用 DaoFoo 和 DaoBar 和 DaoBar 失败怎么办?在这种情况下,您可能希望回滚所有更改,而不仅仅是在DaoBar 中执行的更改。因此需要控制工作单元开始的事务。
恕我直言,开发者需要一些指导。
这是否意味着我的所有服务都应该是事务性的?例如,即使我只是读取数据?
首先,我建议阅读Non-transactional data access and the auto-commit mode(Sessions and transactions 的小弟)来了解“只读事务”。阅读整个页面是值得的,但让我引用这个特定的部分:
许多应用程序开发人员认为他们
可以与 a 之外的数据库通信
交易。这显然不是
可能的; 不能发送SQL语句
到数据库外的数据库
交易。术语非交易性
数据访问意味着没有
明确的事务边界,无
系统事务,并且
数据访问的行为是
自动提交模式。这并不意味着没有
物理数据库事务是
参与。
完成上述链接后,下一个建议阅读将是@Transactional read-only flag pitfalls。以下是相关部分:
(...) 底线是当你
使用基于 ORM 的框架,
只读标志是非常无用的,并且在
大多数情况被忽略。但是如果你
仍然坚持使用它,始终设置
支持的传播模式,如
如清单 9 所示,因此没有事务
开始:
清单 9. 使用只读和SUPPORTS 传播模式进行选择
操作
@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}
更好的是,只是避免使用
@Transactional 注释一共
在进行读操作时,如图
在清单 10 中:
清单 10. 删除选择的 @Transactional 注释
操作
public TradeData getTrade(long tradeId) throws Exception {
return em.find(TradeData.class, tradeId);
}