6

我有一个使用 Spring 2.5 和 Hibernate 3 的应用程序。

有一个带有表示层、服务层和 DAO 层的 Web 应用程序,以及一些共享相同服务和 DAO 层的 Quartz 作业。

事务在不同的层中使用 @Transactional 注释进行初始化,如下所示:

替代文字

它让我遇到了我在这里描述的一个问题:Controlling internal transaction settings from external transaction with Spring 2.5

我读了一些关于如何设置事务以将 Spring 和 Hibernate 连接在一起的内容。看起来推荐的方法是在服务层初始化事务。

我不喜欢的是大多数事务的存在只是因为它们是休眠正常工作所必需的。

当我真的需要一个调用多个服务方法的作业的事务时,似乎我没有选择继续从作业初始化事务。因此,将 @Transactional 注释从 DAO 移动到服务似乎没有任何区别。

您如何建议为此类应用程序设置交易?

4

1 回答 1

5

我读了一些关于如何设置事务以将 Spring 和 Hibernate 连接在一起的内容。看起来推荐的方法是在服务层初始化事务。

确实。事务划分应该在服务层级别进行,而不是在 DAO 层级别:

  • 工作单元是服务,而不是 DAO
  • 如果需要,您希望事务跨越多个 DAO。

我不喜欢的是大多数事务的存在只是因为它们是休眠正常工作所必需的。

您可能应该详细说明这部分,因为事务不是 Hibernate 特定的。

当我真的需要一个调用多个服务方法的作业的事务时,似乎我没有选择继续从作业初始化事务。

如果您想在从 Job 层启动的事务中调用多个服务,请将您的服务声明为具有REQUIRED语义的事务(默认)并依赖 Spring 事务传播(除非您需要远程调用,否则这适用;在这种情况下,请使用 EJB) .

因此,将 @Transactional 注释从 DAO 移动到服务似乎没有任何区别。

确实有所不同,并且在运行批处理时需要从作业层启动事务这一事实并没有使事情有所不同。

我强烈推荐阅读第 9 章。事务管理


(...)我的主要问题来自休眠。对不起,如果我不清楚。

没问题。只是当一个问题含糊不清时,你经常得到一个含糊的答案:)

来自休眠文档:“数据库事务永远不是可选的。与数据库的所有通信都必须发生在事务内部。”。这就是为什么开发人员将 DAO 方法放在我的项目中的原因。

抱歉,上面的声明只是说“与数据库的通信必须发生事务内部”,仅此而已,决定从哪里开始事务由您自行决定(通常是服务层)。如果你在 DAO 级别做,如果调用和MySuperService失败DaoFoo怎么办?在这种情况下,您可能希望回滚所有更改,而不仅仅是在. 因此需要控制工作单元开始的事务。DaoBarDaoBarDaoBar

恕我直言,开发人员需要一些指导。

这是否意味着我的所有服务都应该是事务性的?例如,即使我只是读取数据?

首先,我建议阅读非事务性数据访问和自动提交模式(会话和事务的小弟),以澄清有关“只读事务”的事情。阅读整个页面是值得的,但让我引用这个特定的部分:

许多应用程序开发人员认为他们可以在事务之外与数据库通信。这显然是不可能的;任何 SQL 语句都不能发送到数据库事务之外的数据库。术语非事务性数据访问意味着没有明确的事务边界,没有系统事务,并且数据访问的行为是自动提交模式的行为。这并不意味着不涉及物理数据库事务。

完成上述链接后,下一个建议阅读将是@Transactional read-only flag pitfalls。以下是相关部分:

(...) 最重要的是,当您使用基于 ORM 的框架时,只读标志毫无用处,并且在大多数情况下会被忽略。但是如果您仍然坚持使用它,请始终将传播模式设置为 SUPPORTS,如清单 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);
}
于 2010-10-07T16:18:12.553 回答