通过Spring集成从Hibernate 3迁移到4

本周是时候将我们的代码库升级到最新的Hibernate 4.x了。 我们推迟了迁移(仍在Hibernate 3.3上),因为3.x分支的较新维护版本需要对API进行一些更改,这些更改显然仍在不断变化中。 一个示例是UserType API,该API仍然存在缺陷,将在Hibernate 4中完成。迁移非常顺利。 使UserType适应新界面非常简单。 到处都有一些刺激,但没有痛苦。

需要注意的是Spring集成。 如果您以前将Spring与Hibernate结合使用,则将使用LocalSessionFactoryBean (或AnnotationSessionFactoryBean )创建SessionFactory 。 对于休眠4
在自己的程序包中有一个单独的程序:org.springframework.orm。 hibernate4而不是org.springframework.orm。 休眠3 。 hibernate 4包中的LocalSessionFactoryBean将同时用于映射文件和带注释的实体,因此两种样式都只需要一个。

升级完成后,我们的所有测试都在运行,并且使用本地Hibernate事务管理器在Tomcat上的应用程序也运行良好。 但是,当使用JTA事务(和Spring的JtaTransactionManager )在Glassfish上运行时,在调用sessionFactory.getCurrentSession()时,我们得到了“未找到当前线程的会话”

因此,似乎我错过了与JTA配置有关的内容。 像通常使用Spring-Hibernate集成一样,让Spring驱动事务。 您指定一个事务管理器,Spring确保所有资源都已在事务管理器中注册,并最终调用提交或回滚。 Spring将与Hibernate集成,因此可确保在事务提交之前刷新会话。

使用hibernate 3和hibernate 3 Spring集成时,会话绑定到本地线程。 此技术使您可以使用sessionFactory.getCurrentSession()获取活动事务中任何位置的打开会话。 本地HibernateTransactionManagerJtaTransactionManager都是这种情况。 但是,从hibernate 4集成开始,hibernate会话将绑定到当前正在运行的JTA事务。

从用户的角度来看,什么都没有改变,因为sessionFactory.getCurrentSession()仍会完成其工作。 但是,当运行JTA时,这意味着Hibernate必须能够查找事务管理器以能够向当前正在运行的事务中注册会话。 如果您来自带有Spring的Hibernate 3,这是新的,实际上,您不必在Hibernate SessionFactory (或LocalSessionFactoryBean )配置中配置任何与事务有关的内容。 事实证明,通过Hibernate 4 Spring集成,事务管理器查找配置实际上是由hibernate完成的,而不是由Spring的LocalSessionFactoryBean完成的 。 解决方案非常简单。 将其添加到Hibernate( LocalSessionFactoryBean )配置中解决了我们的问题:

<prop key="hibernate.transaction.jta.platform">
org.hibernate.service.jta.platform.internal.SunOneJtaPlatform
</prop>

然后,应将“ SunOneJtaPlatform”替换为反映您的容器的子类。

有关可用的子类,请参阅API文档 。 此类实际上是在告诉Hibernate如何为您的环境查找事务管理器。 如果您不进行配置,则Hibernate不会将会话绑定到任何东西,因此不会引发异常。 还有一个属性:

hibernate.current_session_context_class

它应该指向org.springframework.orm.hibernate4.SpringSessionContext ,但这是由LocalSessionFactoryBean自动完成的,因此无需在配置中指定它。

解决了我的“当前会话未找到会话”问题后,还有另一个问题。 成功提交事务后,将看不到对事务内部的数据库所做的更改。 经过一番研究,我发现没有人在调用session.flush() 。 在进行hibernate 3集成时,注册了SpringSessionSynchronization ,它将在事务提交之前(在beforeCommmit方法中)调用session.flush( )。

在hibernate 4集成中,注册了SpringFlushSynchronization顾名思义 ,它还将执行刷新。 但是,这仅在TransactionSynchronization的实际“刷新”方法中实现,并且永远不会调用此方法。

我在Spring Bugtracker上对此提出了一个问题 ,其中包括两个示例应用程序,它们清楚地说明了该问题。 第一个使用的是Hibernate 3,另一个使用的是完全相同的应用程序,但是这次使用的是hibernte4。第二个将显示实际上没有任何信息持久化到数据库中(两个应用程序都在最新的Glassfish 3.1.2下进行了测试)。似乎正在创建一个环绕@Transactional注释的冲洗Aspect。 使用order属性,可以命令在刷新Aspect之前应用事务注释。 这样,您的Aspect仍在事务内部运行,并且能够刷新会话。 它可以通过注入SessionFactory (一种方式或另一种方式)然后调用sessionFactory.getCurrentSession()。flush()来以正常方式获取会话。

<tx:annotation-driven order="1">
 
<bean id="flushinAspect" clas="...">
 <property name="order" value="2">
</property></bean>
</tx:annotation-driven>

或者,如果使用注释配置:

@EnableTransactionManagement(order=1)

更新:

关于此问题有一些反馈。 事实证明,这似乎不是Spring Hibernate集成中的错误,而是缺少的Hibernate配置元素。 显然,“ hibernate.transaction.factory_class”需要设置为JTA,默认值为JDBC,它依赖于Hibernate Transaction API进行显式事务管理。 通过将此设置为JTA,休眠将注册必要的同步,该同步将执行刷新。 见春
https://jira.springsource.org/browse/SPR-9404

更新2:

事实证明,在按照上一个问题建议的配置进行纠正后,仍然存在问题。 我将不重复任何事情,您可以在我在此处提交的第二个错误条目中找到详细信息: https : //jira.springsource.org/browse/SPR-9480它基本上可以归结为在JTA场景中在配置了JtaTransactionFactory的情况下,hibernate不会检测到它在事务中,因此将不执行中间刷新。 配置了JtaTransactionFactory之后,您应该通过Hibernate API而不是外部(在我们的例子中为Spring)机制来控制事务。 副作用之一是在某些情况下您可能正在读取陈旧的数据。

例:

//[START TX1]
Query query = session.createQuery('from Person p where p.firstName = :firstName and p.lastName = :lastName');
Person johnDoe = (Person)query.setString('firstName','john').setString('lastName','doe').uniqueResult();
johnDoe.setFirstName('Jim');
Person jimDoe = (Person)query.setString('firstName','jim').setString('lastName','doe').uniqueResult();
//[END TX1]

发生的情况是,在第5行执行第二个查询时,hibernate应该检测到它应该刷新对第4行的附加实体所做的先前更新(将名称从“ john”更新为“ jim”)。 但是,由于休眠不知道它在一个活动事务中运行,因此中间刷新不起作用。 在事务提交之前,它将仅刷新一次。 这会导致数据过时,因为第二个查询将找不到“ jim”,而是返回null。 解决方案(请参阅问题中Juergen Hoeller的答复)是将hibernate.transaction.factory_class配置为org.hibernate.transaction.CMTTransactionFactory 。 刚开始我有点怀疑,因为CMT使EJB容器成为现实。 但是,如果您阅读有关CMTTransaction的Java文档,则确实有道理:

/**
 * Implements a transaction strategy for Container Managed Transaction (CMT) scenarios.  All work is done in
 * the context of the container managed transaction.
 *
 * The term 'CMT' is potentially misleading; the pertinent point simply being that the transactions are being
 * managed by something other than the Hibernate transaction mechanism.
 *
 * Additionally, this strategy does *not* attempt to access or use the {@link javax.transaction.UserTransaction} since
 * in the actual case CMT access to the {@link javax.transaction.UserTransaction} is explicitly disallowed.  Instead
 * we use the JTA {@link javax.transaction.Transaction} object obtained from the {@link TransactionManager}

之后,一切似乎都正常。 综上所述,如果您希望休眠状态通过UserTransaction管理JTA事务,则应使用JtaTransactionFactory。 在这种情况下,您必须使用Hibernate API来控制事务。 如果还有其他人管理事务(Spring,EJB容器……),则应改用CMTTransactionFactory。 然后,通过使用javax.transaction.TransactionManager检查活动的javax.transaction.Transaction,Hibernate将恢复为注册同步。 如果弹出任何其他问题,我将相应地更新此条目。

参考:Koen Serneels –技术博客博客上,我们的JCG合作伙伴 Koen Serneels 通过Spring集成从Hibernate 3迁移到4

翻译自: https://www.javacodegeeks.com/2013/03/migrating-from-hibernate-3-to-4-with-spring-integration.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值