Spring4 + Hibernate4 + JTA写操作失败

时间:2014-10-29 18:18:47

标签: jta wildfly spring-transactions hibernate-4.x spring-4

我正在将JBoss 5应用程序上的旧版Spring 3,Hibernate 3,JTA迁移到最新版本(Spring 4.1.0.RELEASE,Hibernate 4.3.6.Final,JBoss Wildfly 8.1)。似乎Spring 4.1.0.RELEASE和Hibernate 4.3.6.Final做 NOT 一起支持使用 LocalSessionFactoryBean HibernateTransactionManager <进行写操作的事务/ em>如下配置。只读获取操作似乎正常工作。

要迁移,org.springframework.orm。 hibernate3 .support.HibernateDaoSupport已更新为org.springframework.orm。 hibernate4 .support.HibernateDaoSupport。有问题的代码试图用 getHibernateTemplate()。saveOrUpdate(myObject); 保存,其中 myObject 是要保存的对象(在Spring3 + Hibernate 3中有效)。代码编译但在运行时我看到代码在以下处调用异常:

https://github.com/spring-projects/spring-framework/blob/master/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateTemplate.java#L325

问题:

  1. getSessionFactory()。getCurrentSession()触发的Hibernate会话的打开/关闭是否会调用问题(性能还是其他)?如果是这样,配置中是否有可以设置以避免它的东西?

  2. 在处理异常时,HibernateTemplate始终将新打开的会话设置为FlushMode.MANUAL。而且,在调试器中,我看到这无法检查写操作:

  3. https://github.com/spring-projects/spring-framework/blob/master/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateTemplate.java#L1134

    请注意,设置 getHibernateTemplate()。setCheckWriteOperations(false); 绕过Spring检查,但 getHibernateTemplate()。saveOrUpdate(myObject)调用在Hibernate代码中无声地失败没有抛出任何异常,也没有任何东西写入数据库。我需要做什么配置更改才能提交写操作?

    Bean定义:

    这里是来自application-context.xml Spring配置文件的相关bean定义片段:

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
    
    <tx:annotation-driven/>
    
    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="false">
        <property name="jndiName" value="java:jboss/datasources/jdbc/my-srvr"/>
        <property name="cache">
            <value>false</value>
        </property>
        <property name="proxyInterface">
            <value>javax.sql.DataSource</value>
        </property>
    </bean>
    
    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" lazy-init="true">
    
        <property name="dataSource" ref="dataSource"/>
    
        <property name="mappingResources">
            <list>
                <value>com/mydomain/dao/Hib.hib.xml</value>
            </list>
        </property>
    
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.generate_statistics">false</prop>
    
                <!-- JTA  -->
                <prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory</prop>
                <prop key="hibernate.flushMode">AUTO</prop>
                <prop key="jta.UserTransaction">java:jboss/UserTransaction</prop>
                <prop key="jta.TransactionManager">java:jboss/TransactionManager</prop>
                <prop key="hibernate.transaction.jta.platform">org.hibernate.engine.transaction.jta.platform.internal.JBossAppServerJtaPlatform</prop>
                <prop key="hibernate.current_session_context_class">org.hibernate.context.internal.JTASessionContext</prop>
                <!--prop key="hibernate.transaction.manager_lookup_class">
                    org.hibernate.transaction.JBossTransactionManagerLookup
                </prop-->
    
                <!-- Turn caching off to focus on JTA issues-->
                <prop key="hibernate.cache.use_second_level_cache">false</prop>
                <prop key="hibernate.cache.use_query_cache">false</prop>
                <!--prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop-->
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
    
                <prop key="net.sf.ehcache.configurationResourceName">sample-ehcache.xml</prop>
            </props>
        </property>
        <!--No equivalent class in Spring4; comment out for now-->
        <!--property name="eventListeners">
            <map>
                <entry key="merge">
                    <bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
                </entry>
            </map>
        </property-->
    </bean>
    

    注意:遗留bean定义的一个重要更改是从org.springframework。 transaction.jta.JtaTransactionManager 更改为org.springframework。 orm.hibernate4.HibernateTransactionManager

    JNDI查看

    一旦部署,JBoss Wildfly中的JNDI视图如下(当然对象引用会改变每个部署):

    java:jboss

    TransactionManager TransactionManagerDelegate @ 49e6e9c8

    TransactionSynchronizationRegistry TransactionSynchronizationRegistryImple @ 40cd0746

    UserTransaction UserTransaction

    jaas java:jboss / jaas / Context proxy

1 个答案:

答案 0 :(得分:0)

所以我终于让写操作在遗留代码中工作了。以下是我为使代码工作所遵循的步骤:

  1. 确保您使用的是Hibernate特定的事务管理器 org.springframework.orm.hibernate4.HibernateTransactionManager NOT 通用 org.springframework。 transaction.jta.JtaTransactionManager

  2. 验证是否已启用注释。

  3. @Transactional 注释(org.springframework.transaction.annotation.Transactional)添加到执行保存/更新/删除等操作的方法中。遗留代码在不需要此注释的情况下工作,但现在,对于最新版本,启用写入操作必需

  4. 在我的情况下,我在添加注释后遇到了一堆自动布线问题。根本原因是,某些实现类(而不是接口)被用于在@Service级别类中自动连接属性。更改引用以使用修复该问题的接口。您可以在其他主题上阅读有关它的更多信息,例如this one

  5. 我必须搜索并重复这些步骤来修复遗留代码中的所有此类实例。请注意,通过OpenSessionInViewFilter全局设置 FlushMode AUTO 并不是一个干净的解决方案;有一个很好的理由,为什么Spring默认将 FlushMode 设置为 MANUAL 。当存在@Transactional注释时,Spring会进行必要的运行时调整以支持写操作。我一直调试到Hibernate org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl类,Jta同步与上面的设置一起正常工作。希望这有助于任何人试图将遗留代码迁移到最新版本。