如何使用Spring和Hibernate为Web应用程序和批处理作业设置事务

Dam*_*ien 5 jobs spring hibernate transactions web-applications

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

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

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

替代文字

它引发了我在这里描述的一个问题:使用Spring 2.5从外部事务控制内部事务设置

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

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

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

您如何建议为此类应用程序设置事务?

Pas*_*ent 5

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

当然.事务划分应在服务层级别完成,而不是在DAO层级别完成:

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

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

您应该详细说明这一部分,因为事务不是特定于Hibernate的.

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

如果要调用多个服务从作业层发起的事务中,与交易申报您的服务REQUIRED语义(默认值)和依赖于Spring事务传播(适用,除非你需要远程调用;在这种情况下,使用的EJB) .

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

确实有所作为,您在运行批不使事情变得不同,当需要从工作层发起交易的事实.

我热烈建议阅读第9章.事务管理.


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

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

Hibernate文档:"数据库事务绝不是可有可无的与数据库的所有通信都在事务中发生.".这就是为什么开发人员将DAO方法交易放在我的项目上的原因.

很抱歉,但上述声明只表示"与数据库的通信必须事务中发生",仅此而已,并决定从何处开始交易由您自行决定(通常是服务层).如果你在DAO层面做到这一点,如果有什么MySuperService电话DaoFoo,并DaoBarDaoBar失败?在这种情况下,您可能希望回滚所有更改,而不仅仅是那些更改DaoBar.因此需要控制工作单元开始的交易.

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

这是否意味着我的所有服务都应该是交易性的?即使我只是阅读数据?

首先,我建议阅读非事务性数据访问和自动提交模式(Sessions和事务的小兄弟)来澄清"只读事务"的内容.阅读整个页面是值得的,但让我引用这个特定的部分:

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

一旦你完成上述链接,下一个建议的读数将是@Transactional只读标志陷阱.以下是相关部分:

(...)最重要的是,当您使用基于ORM的框架时,只读标志是无用的,在大多数情况下会被忽略.但是如果您仍然坚持使用它,请始终将传播模式设置为SUPPORTS,如清单9所示,因此不会启动任何事务:

清单9.使用只读和SUPPORTS传播模式进行选择操作

@Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public TradeData getTrade(long tradeId) throws Exception {
   return em.find(TradeData.class, tradeId);
}
Run Code Online (Sandbox Code Playgroud)

更好的是,@Transactional在执行读取操作时完全避免使用 注释,如清单10所示:

清单10.删除@Transactionalselect操作的注释

public TradeData getTrade(long tradeId) throws Exception {
   return em.find(TradeData.class, tradeId);
}
Run Code Online (Sandbox Code Playgroud)