【问题标题】:Hibernate EntityManager with getSessionFactoryGetCurrentSession()使用 getSessionFactoryGetCurrentSession() 休眠 EntityManager
【发布时间】:2013-09-16 14:04:56
【问题描述】:

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

getSessionFactory().getCurrentSession().

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

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

【问题讨论】:

  • 请贴出与事务管理相关的代码(部分xml应用上下文、带有@Transactional注释的示例代码或事务方法的xml声明,如果你使用的话)
  • 我在我的问题中写道即使上面的代码也是在事务块中执行的。所以即使带有@Transactional 注释或事务方法的xml 声明的代码也会发生异常
  • 是的...但是您是否检查过交易是否真正开始? -您可以通过启用适当的记录器来简单地检查这一点-(如果在其他地方配置错误,@Transactional 可能完全不做任何事情。)
  • 我检查了事务资源(在调试模式下)并使用 EntityManagerFactory 键,会话存在但不在 SessionFactory 键下!

标签: java hibernate jpa


【解决方案1】:

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

    private static Session getSessionFromEM(final EntityManager entityManager){
    return entityManager.unwrap(Session.class);
}

【讨论】:

    【解决方案2】:

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

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

    想法是这样的:在你的SessionFactoryBean中使用CurrentSessionContext的自定义实现,这个自定义实现会在事务资源中搜索当前事务的实体管理器;当发现只是调用IIla发布的代码来获取hibernate Session。

    这样做:

    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 需要带有SessionFactoryImplementor 的构造函数,我认为 Hibernate-3 需要带有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)

    【讨论】:

    • @nir 你试过了吗?它为你运行吗?
    猜你喜欢
    • 2013-01-13
    • 2012-10-17
    • 2014-11-14
    • 2017-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多