You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring 6/Hibernate 6升级后SessionFactory无CurrentSessionContext配置问题

Hibernate 6.6 + Spring 6.2 会话管理升级问题解析

一、旧版本(Spring 5.3 + Hibernate 5.6)工作原理

你之前的实现能正常工作,核心是Spring对SessionFactory的代理机制:

  • 通过LocalContainerEntityManagerFactoryBean创建的SessionFactory并非Hibernate原生实例,而是Spring生成的代理对象。
  • 当进入@Transactional方法时,Spring事务管理器会通过HibernateJpaDialect自动创建Session并绑定到Spring的会话上下文。
  • 调用sessionFactory.getCurrentSession()时,Spring代理会拦截该方法,直接返回当前事务上下文里已打开的Session,无需依赖Hibernate原生的会话上下文配置。

二、升级后失效的原因

Spring 6.2对JPA容器的代理逻辑做了调整:

  • 直接注入的SessionFactory现在是Hibernate原生的SessionFactoryImpl,不再被Spring代理。
  • 此时调用getCurrentSession()只会使用Hibernate自身的会话上下文(比如你配置的thread),但Spring的事务管理是绑定到JPA EntityManager上下文的,两者没有关联,所以无法获取事务内已打开的Session。
  • 而@PersistenceContext注入的Session本质是Spring管理的EntityManager的Hibernate Session包装,天然和事务上下文绑定,因此能正常工作。

三、恢复原有工作方式的可行方案

方案1:配置Hibernate使用Spring会话上下文

在persistence.xml的持久化单元中添加以下配置,让Hibernate直接使用Spring的会话上下文实现,打通和Spring事务的关联:

<persistence-unit name="JPATest" >
    <!-- 原有配置 -->
    <properties>
        <property name="hibernate.current_session_context_class" value="org.springframework.orm.hibernate6.SpringSessionContext"/>
    </properties>
</persistence-unit>

注意:Hibernate 6对应的Spring会话上下文类路径是org.springframework.orm.hibernate6.SpringSessionContext,Hibernate 5是org.springframework.orm.hibernate5.SpringSessionContext,请匹配你的版本。

方案2:让Spring代理原生SessionFactory

通过Spring的ProxyFactoryBean为原生SessionFactory创建代理,保留Spring对getCurrentSession()的拦截逻辑:

<!-- 原有的LocalContainerEntityManagerFactoryBean,改个ID -->
<bean id="originalSessionFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="JPATest" />
    <property name="persistenceXmlLocation" value="classpath:persistence.xml" />
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter" ref="vendorAdapter" />
    <property name="jpaDialect">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
    </property>
</bean>

<!-- 创建Spring代理的SessionFactory -->
<bean id="sessionFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="originalSessionFactory"/>
    <property name="interceptorNames">
        <list>
            <value>org.springframework.orm.hibernate6.HibernateInterceptor</value>
        </list>
    </property>
</bean>

之后保持原有@Resource(name = "sessionFactory")的注入方式即可,代理后的SessionFactory会在事务内返回正确的Session。

方案3:自定义SessionFactory包装类

如果无法修改注入点或配置,可以编写一个包装类,内部通过Spring的SessionFactoryUtils获取事务绑定的Session:

public class SpringManagedSessionFactory implements SessionFactory {
    private final SessionFactory delegate;

    public SpringManagedSessionFactory(SessionFactory delegate) {
        this.delegate = delegate;
    }

    @Override
    public Session getCurrentSession() throws HibernateException {
        // 利用Spring工具类获取事务内的Session
        return SessionFactoryUtils.getCurrentSession(delegate);
    }

    // 其他SessionFactory方法直接委托给原生实例
    @Override
    public Session openSession() throws HibernateException {
        return delegate.openSession();
    }

    // 实现SessionFactory接口的所有其他方法...
}

然后在配置中替换原有的SessionFactory bean:

<bean id="sessionFactory" class="your.package.SpringManagedSessionFactory">
    <constructor-arg ref="originalSessionFactory"/>
</bean>

<bean id="originalSessionFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <!-- 原有的配置 -->
</bean>

内容的提问来源于stack exchange,提问作者Steven Miller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:16:05