在遗留的HibernateTemplate代码和JPA代码之间共享Hibernate会话

时间:2014-04-06 10:22:25

标签: java spring hibernate jpa

我使用标准的LocalSessionFactoryBeanSolution使用Spring(3.2.x)+ Hibernate(3.6.10)开发了一个相当大的项目。

最近我想通过hibernate切换到JPA,以便能够使用Spring Data JPA功能。这是所有南下的时刻。事实证明Hibernate会话分辨率因基于HibernateTemplate的类和基于EntityManager的clasess而异。我无法将所有hibernate + hibernatetemplate代码迁移到JPA - 这简直太过分了。

由于一个测试案例的价值超过1000字,因此只需将此测试用例失败:

@Test
@Transactional
public void test0() {
    HibernateTemplate template = new HibernateTemplate( sessionFactory );
    User user = template.execute( new HibernateCallback<User>() {
        @Override
        public User doInHibernate( Session session ) throws HibernateException, SQLException {
            return (User) session.load( User.class,
                                        1l );
        }
    } );

    Session session = entityManager.unwrap( Session.class );
    Assert.assertTrue( session.contains( user ) );
}

我唯一能做的就是参与一些&#34; AspectJ魔术&#34;。我成功地完成了这方面的工作:

@Aspect
public class Hibernate2JpaMigrationFixes {
    @SuppressWarnings("unused")
    private final static Logger    log    = LoggerFactory.getLogger( Hibernate2JpaMigrationFixes.class );

    @PersistenceContext
    private EntityManager        entityManager;

    @Around("execution( * org.springframework.orm.hibernate3.HibernateTemplate.isAllowCreate())")
    public Object disallowHibernateSessionCreation( ProceedingJoinPoint pjp ) {
        return Boolean.FALSE;
    }

    @Around("execution( * org.springframework.orm.hibernate3.HibernateTemplate.clear())")
    public void disallowClear( ProceedingJoinPoint pjp ) {
        throw new RuntimeException( "clear not allowed" );
    }

    @Around("execution( * org.springframework.orm.hibernate3.HibernateTemplate.getSession())")
    public Object useTheSameSessionEntityManagerDoes( ProceedingJoinPoint pjp ) {
        return entityManager.unwrap( Session.class );
    }
}

我还试图摆弄hibernate.current_session_context_class - 该类被实例化 - 仍然从未用于解析当前会话。

我的spring + hibernate配置如下:

<bean id="pum" class="org.springframework.data.jpa.support.MergingPersistenceUnitManager">
    <property name="packagesToScan" value="com.xxx.persistence,com.xxx.smart,com.xxx.clientapp.server.model" />
    <property name="defaultDataSource" ref="dataSource" />
</bean>

<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter" ref="jpaAdapter" />
    <property name="jpaDialect" ref="jpaDialect" />
    <property name="persistenceUnitManager" ref="pum" />
    <property name="jpaPropertyMap">
        <map>
            <entry key="javax.persistence.validation.factory" value-ref="validator" />
            <entry key="hibernate.dialect" value="${hibernate.dialect}" />
            <entry key="hibernate.show_sql" value="${hibernate.show_sql}" />
            <entry key="hibernate.ejb.naming_strategy" value="com.mobilebox.persistence.hibernate.CustomNamingStrategy" />
            <!--
            <entry key="hibernate.current_session_context_class" value="org.springframework.orm.hibernate3.SpringSessionContext" />
             -->
        </map>
    </property>
</bean>

<!-- transaction management -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"
    p:jpaDialect-ref="jpaDialect" />

<!-- legacy -->
<bean id="sessionFactory" class="org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean" />
<bean id="baseHibernateDao" abstract="true" p:sessionFactory-ref="sessionFactory" />

<!-- nowe dao -->
<jpa:repositories base-package="com.xxx.smart.dao" />
<jpa:repositories base-package="com.xxx.smart.repository" />

仍然只是觉得我错过了一些东西。没有这种黑客攻击,我能做些什么吗?

1 个答案:

答案 0 :(得分:0)

@Transactional如果它正常工作会导致会话绑定到该线程。然后要使用会话,模板需要配置一些标志,尝试设置这些标志,以防止模板创建新会话:

HibernateTemplate template = new HibernateTemplate( sessionFactory );

template.setAllowCreate(false);
template.setAlwaysUseNewSession(false);

请注意@Transactional可能无法正常工作,如果是,则没有会话绑定到该线程。在这些情况下,与实体管理器的每次交互都在其自己的会话中运行,该会话仅为该查询创建和销毁,并且仅返回分离的实体。

要使这两件事都有效,请尝试确保以下两件事情按预期工作:

  • @Transactional需要正常工作,这可以通过在方法中设置断点并检查调试跟踪以查看事务方面是否包装方法来确认。如果是,则会话绑定到该线程。

  • 需要配置hibernate模板以从线程中检索会话,通过在HibernateTemplate.getSession()

  • 中设置一些断点,可以确认这是有效的