如何使用 Spring 和 Hibernate 为 Web 应用程序和批处理作业设置事务
Posted
技术标签:
【中文标题】如何使用 Spring 和 Hibernate 为 Web 应用程序和批处理作业设置事务【英文标题】:How to set-up transactions for both web application and batch jobs using Spring and Hibernate 【发布时间】:2011-04-22 10:21:17 【问题描述】:我有一个使用 Spring 2.5 和 Hibernate 3 的应用程序。
有一个 Web 应用程序具有表示层、服务层和 DAO 层,以及一些共享相同服务和 DAO 层的 Quartz 作业。
事务在不同的层用@Transactional注解初始化,像这样:
这导致了我在这里描述的一个问题:Controlling inner transaction settings from outer transaction with Spring 2.5
我阅读了一些关于如何设置事务以将 Spring 和 Hibernate 连接在一起的内容。看起来推荐的方法是在服务层初始化事务。
我不喜欢的是大多数事务的存在只是因为它们是休眠正常工作所必需的。
当我真的需要一个事务来调用多个服务方法的作业时,我似乎没有选择继续从作业初始化事务。所以将 @Transactional 注释从 DAO 移动到服务似乎没有任何区别。
您建议如何为此类应用程序设置交易?
【问题讨论】:
很好的问题,我正要自己问:) 帮助一个问题并不像帮助一个答案那么令人高兴,但还是很高兴听到;o) 【参考方案1】:我阅读了一些关于如何设置事务以将 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);
【讨论】:
感谢您的解释帕斯卡。我显然阅读了第 9 章,但我的主要问题来自 Hibernate。对不起,如果我不清楚。来自休眠文档:“数据库事务永远不是可选的。与数据库的所有通信都必须在事务内部进行。”。这就是为什么开发人员将 DAO 方法放在我的项目中的原因。这是否意味着我的所有服务都应该是事务性的?例如,即使我只是读取数据? @Pascal 感谢您的时间和澄清。 帕斯卡有什么你不知道的吗? 我也想知道,帕斯卡,请告诉我们,上帝存在吗? :o) @willcodejavaforfood @Damien LOL 伙计们。我显然不知道一切,只是想解决这个问题:) 而且,你知道,如果上帝存在,谁创造了上帝?作为旁注,你看过George Carlin吗? :D以上是关于如何使用 Spring 和 Hibernate 为 Web 应用程序和批处理作业设置事务的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring 和 Hibernate 为 Web 应用程序和批处理作业设置事务
使用 spring 和 hibernate 时,如何处理会话/事务?
如何使用 JPQL、Spring Data Repositories 和 Hibernate 为 TimescaleDB `time_bucket` 函数参数化 Postgresql 间隔