javascript
通过Spring集成从Hibernate 3迁移到4
本周是時候?qū)⑽覀兊拇a庫升級到最新的Hibernate 4.x了。 我們推遲了遷移(仍在Hibernate 3.3上),因為3.x分支的較新維護版本需要對API進行一些更改,這些更改顯然仍在不斷變化中。 一個示例是UserType API,該API仍然存在缺陷,將在Hibernate 4中完成。遷移非常順利。 使UserType適應新界面非常簡單。 到處都有一些刺激,但沒有痛苦。
需要注意的是Spring集成。 如果您以前將Spring與Hibernate結(jié)合使用,則將使用LocalSessionFactoryBean (或AnnotationSessionFactoryBean )創(chuàng)建SessionFactory 。 對于休眠4
在自己的程序包中有一個單獨的程序:org.springframework.orm。 hibernate4而不是org.springframework.orm。 休眠3 。 hibernate 4包中的LocalSessionFactoryBean將同時用于映射文件和帶注釋的實體,因此兩種樣式都只需要一個。
升級完成后,我們的所有測試都在運行,并且使用本地Hibernate事務管理器在Tomcat上的應用程序也運行良好。 但是,當使用JTA事務(和Spring的JtaTransactionManager )在Glassfish上運行時,在調(diào)用sessionFactory.getCurrentSession()時,我們得到了“未找到當前線程的會話” 。
因此,似乎我錯過了與JTA配置有關(guān)的內(nèi)容。 像通常使用Spring-Hibernate集成一樣,讓Spring驅(qū)動事務。 您指定一個事務管理器,Spring確保所有資源都已在事務管理器中注冊,并最終調(diào)用提交或回滾。 Spring將與Hibernate集成,因此可確保在事務提交之前刷新會話。
使用hibernate 3和hibernate 3 Spring集成時,會話綁定到本地線程。 此技術(shù)使您可以使用sessionFactory.getCurrentSession()獲取活動事務中任何位置的打開會話。 本地HibernateTransactionManager和JtaTransactionManager都是這種情況。 但是,從hibernate 4集成開始,hibernate會話將綁定到當前正在運行的JTA事務。
從用戶的角度來看,什么都沒有改變,因為sessionFactory.getCurrentSession()仍會完成其工作。 但是,當運行JTA時,這意味著Hibernate必須能夠查找事務管理器以能夠向當前正在運行的事務中注冊會話。 如果您來自帶有Spring的Hibernate 3,這是新的,實際上,您不必在Hibernate SessionFactory (或LocalSessionFactoryBean )配置中配置任何與事務有關(guān)的內(nèi)容。 事實證明,通過Hibernate 4 Spring集成,事務管理器查找配置實際上是由hibernate完成的,而不是由Spring的LocalSessionFactoryBean完成的 。 解決方案非常簡單。 將其添加到Hibernate( LocalSessionFactoryBean )配置中解決了我們的問題:
<prop key="hibernate.transaction.jta.platform"> org.hibernate.service.jta.platform.internal.SunOneJtaPlatform </prop>然后,應將“ SunOneJtaPlatform”替換為反映您的容器的子類。
有關(guān)可用的子類,請參閱API文檔 。 此類實際上是在告訴Hibernate如何為您的環(huán)境查找事務管理器。 如果您不進行配置,則Hibernate不會將會話綁定到任何東西,因此不會引發(fā)異常。 還有一個屬性:
hibernate.current_session_context_class它應該指向org.springframework.orm.hibernate4.SpringSessionContext ,但這是由LocalSessionFactoryBean自動完成的,因此無需在配置中指定它。
解決了我的“當前會話未找到會話”問題后,還有另一個問題。 成功提交事務后,將看不到對事務內(nèi)部的數(shù)據(jù)庫所做的更改。 經(jīng)過一番研究,我發(fā)現(xiàn)沒有人在調(diào)用session.flush() 。 在進行hibernate 3集成時,注冊了SpringSessionSynchronization ,它將在事務提交之前(在beforeCommmit方法中)調(diào)用session.flush( )。
在hibernate 4集成中,注冊了SpringFlushSynchronization , 顧名思義 ,它還將執(zhí)行刷新。 但是,這僅在TransactionSynchronization的實際“刷新”方法中實現(xiàn),并且永遠不會調(diào)用此方法。
我在Spring Bugtracker上對此提出了一個問題 ,其中包括兩個示例應用程序,它們清楚地說明了該問題。 第一個使用的是Hibernate 3,另一個使用的是完全相同的應用程序,但是這次使用的是hibernte4。第二個將顯示實際上沒有任何信息持久化到數(shù)據(jù)庫中(兩個應用程序都在最新的Glassfish 3.1.2下進行了測試)。似乎正在創(chuàng)建一個環(huán)繞@Transactional注釋的沖洗Aspect。 使用order屬性,可以命令在刷新Aspect之前應用事務注釋。 這樣,您的Aspect仍在事務內(nèi)部運行,并且能夠刷新會話。 它可以通過注入SessionFactory (一種方式或另一種方式)然后調(diào)用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)更新:
關(guān)于此問題有一些反饋。 事實證明,這似乎不是Spring Hibernate集成中的錯誤,而是缺少的Hibernate配置元素。 顯然,“ hibernate.transaction.factory_class”需要設置為JTA,默認值為JDBC,它依賴于Hibernate Transaction API進行顯式事務管理。 通過將此設置為JTA,休眠將注冊必要的同步,該同步將執(zhí)行刷新。 見春
https://jira.springsource.org/browse/SPR-9404
更新2:
事實證明,在按照上一個問題建議的配置進行糾正后,仍然存在問題。 我將不重復任何事情,您可以在我在此處提交的第二個錯誤條目中找到詳細信息: https : //jira.springsource.org/browse/SPR-9480它基本上可以歸結(jié)為在JTA場景中在配置了JtaTransactionFactory的情況下,hibernate不會檢測到它在事務中,因此將不執(zhí)行中間刷新。 配置了JtaTransactionFactory之后,您應該通過Hibernate API而不是外部(在我們的例子中為Spring)機制來控制事務。 副作用之一是在某些情況下您可能正在讀取陳舊的數(shù)據(jù)。
例:
//[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]發(fā)生的情況是,在第5行執(zhí)行第二個查詢時,hibernate應該檢測到它應該刷新對第4行的附加實體所做的先前更新(將名稱從“ john”更新為“ jim”)。 但是,由于休眠不知道它在一個活動事務中運行,因此中間刷新不起作用。 在事務提交之前,它將僅刷新一次。 這會導致數(shù)據(jù)過時,因為第二個查詢將找不到“ jim”,而是返回null。 解決方案(請參閱問題中Juergen Hoeller的答復)是將hibernate.transaction.factory_class配置為org.hibernate.transaction.CMTTransactionFactory 。 剛開始我有點懷疑,因為CMT使EJB容器成為現(xiàn)實。 但是,如果您閱讀有關(guān)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} 之后,一切似乎都正常。 綜上所述,如果您希望休眠狀態(tài)通過UserTransaction管理JTA事務,則應使用JtaTransactionFactory。 在這種情況下,您必須使用Hibernate API來控制事務。 如果還有其他人管理事務(Spring,EJB容器……),則應改用CMTTransactionFactory。 然后,通過使用javax.transaction.TransactionManager檢查活動的javax.transaction.Transaction,Hibernate將恢復為注冊同步。 如果彈出任何其他問題,我將相應地更新此條目。
參考:在Koen Serneels –技術(shù)博客博客上,我們的JCG合作伙伴 Koen Serneels 通過Spring集成從Hibernate 3遷移到4 。
翻譯自: https://www.javacodegeeks.com/2013/03/migrating-from-hibernate-3-to-4-with-spring-integration.html
總結(jié)
以上是生活随笔為你收集整理的通过Spring集成从Hibernate 3迁移到4的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 成都民俗 成都的风俗介绍
- 下一篇: 为MongoDB定制Spring Soc