2

我更改了我的应用程序以使用 Hibernate EntityManager(来自 Hibernate 会话),
但我有一些旧代码(我无法更改这些代码)在以下代码中使用:

getSessionFactory().getCurrentSession().

我有 sessionFactory 的 bean,所以上面的代码应该可以工作,但在运行时我有
HibernateException("No Session found for current thread"),甚至上面的代码也是在事务块中执行的。

仅供参考:我检查了事务资源(在调试模式下)并使用 EntityManagerFactory 键,会话存在但不在 SessionFactory 键下

4

2 回答 2

8

我建议你这样做(看起来很老套,但对于遗留代码,有时需要)

此方案使用 Spring TransactionSynchronizationManager和 Hibernate 4,但可以适应其他 Hibernate 版本。

这里的想法是:在你的 SessionFactoryBean 中使用CurrentSessionContext的自定义实现,这个自定义实现将在事务资源中搜索当前事务的实体管理器;当发现只需调用 IIla 发布的代码即可获取休眠会话。

去做吧 :

1.在hibernateProperties中定义属性hibernate.current_session_context_class

<bean id="sessionFactory"
      class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    ...
    <property name="hibernateProperties">
        <props>
            ...
            <prop key="hibernate.current_session_context_class">
                com.example.jpa.HibernateSessionInEntityManager
            </prop>
        </props>
    </property>
</bean>

<!-- for completness : here are the other relevant beans -->

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="com.example.jpa.validator"/>
</bean>

<bean id="transactionManager"
      class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="dataSource" ref="dataSource" />
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

2.实现您的自定义 CurrentSessionContext : HibernateSessionInEntityManager.java

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.ejb.EntityManagerImpl;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.persistence.EntityManager;
import java.util.Map;

public class HibernateSessionInEntityManager implements CurrentSessionContext {

    public HibernateSessionInEntityManager() {
    }

    public HibernateSessionInEntityManager(SessionFactory sessionFactory) {
    }

    public HibernateSessionInEntityManager(SessionFactoryImplementor sessionFactory) {
    }

    public Session currentSession() throws HibernateException {
        Map<Object, Object> resourceMap = TransactionSynchronizationManager.getResourceMap();
        for(Object v:resourceMap.values()){
            if(v instanceof EntityManagerHolder){
                return getSessionFromEM(((EntityManagerHolder)v).getEntityManager());
            }
        }
        return null;
    }

    private static Session getSessionFromEM(final EntityManager entityManager)
    {
        final Object emDelegate = entityManager.getDelegate();
        if (emDelegate instanceof EntityManagerImpl)
        {
            return ((EntityManagerImpl) emDelegate).getSession();
        }
        else if (emDelegate instanceof Session)
        {
            return (Session) emDelegate;
        }
        throw new HibernateException("No Session found");
    }
 }

注意所有这些构造函数:Hibernate-4 需要一个 withSessionFactoryImplementor而我认为 Hibernate-3 需要一个 with SessionFactory。(可能不需要无参数构造函数)

3.这里有一个简单的测试用例来验证它是否有效

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:ApplicationContext.xml" })
public class HibernateSessionInEntityManagerTest {

    @Autowired
    public SessionFactory sessionFactory;

    @Test
    @Transactional
    public void testGetHibernateSession(){
        Session session = sessionFactory.getCurrentSession();
        Assert.assertNotNull(session);
    }
}

我希望它会有所帮助。(顺便说一句:好问题)

重要说明:如果您有多个 EntityManagerFactoryBean 在查看事务资源时要小心选择好的一个。(例如,查看关联 entityManagerFactory 的 persistenceUnitName)

于 2013-09-13T10:39:16.463 回答
0

“getSessionFromEM”方法的更短的实现:

    private static Session getSessionFromEM(final EntityManager entityManager){
    return entityManager.unwrap(Session.class);
}
于 2015-11-03T15:19:31.843 回答