【问题标题】:Sharing Hibernate Session between legacy HibernateTemplate code and JPA code在遗留 HibernateTemplate 代码和 JPA 代码之间共享 Hibernate Session
【发布时间】:2014-05-18 12:50:02
【问题描述】:

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

最近我想通过 hibernate 切换到 JPA,以便能够使用 Spring Data JPA 功能。这是所有南下的时刻。事实证明,基于 HibernateTemplate 的类和基于 EntityManager 的类的 Hibernate 会话分辨率不同。我无法将我所有的 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 ) );
}

我唯一能做的就是加入一些“AspectJ 魔法”。我设法使这一切都与这方面有关:

@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" />

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

【问题讨论】:

  • 我已经发布了一些可能的原因,如果您可以尝试一下并回复发生的情况(重要:如果太大,请发布完整的堆栈跟踪,并带有指向 pastebin.com 的链接)
  • Spring 默认将hibernate.current_session_context_class 设置为 Spring 类。如果您有 persistence.xml 文件,请发布。基本上你的配置应该可以工作。另请注意,session.load 并没有做太多,它只是构建一个代理,而session.get 实际上是从数据库中检索元素!。

标签: java spring hibernate jpa


【解决方案1】:

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

HibernateTemplate template = new HibernateTemplate( sessionFactory );

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

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

要让这两项工作都正常工作,请尝试确保以下两个工作按预期工作:

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

  • 需要将休眠模板配置为从线程中检索会话,这可以通过在HibernateTemplate.getSession()中设置一些断点来确认它是否正常工作

【讨论】:

    猜你喜欢
    • 2014-09-24
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 2011-03-02
    • 2021-09-18
    • 1970-01-01
    相关资源
    最近更新 更多