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

异常场景下如何关闭并重新打开Hibernate Session

哥们,针对你这个Spring+Hibernate结合open-session-in-conversation-filter的场景,我来给你捋捋怎么处理异常时的Session重建问题:

核心思路先明确

你当前的模式下,Session是和请求会话绑定的,但因为每次插入/更新都单独提交事务,一旦某步操作抛异常,当前Session可能处于脏状态(比如有未完成的持久化操作残留),这时候必须先清理掉旧Session,再重建新的才能继续后续操作。

方案一:手动干预Session生命周期(适合局部异常处理)

如果只是在特定操作的异常捕获里处理,可以直接借助Spring的SessionFactoryUtils和TransactionSynchronizationManager来手动管理:

try {
    // 你的插入/更新操作逻辑
    someDao.insertEntity(entity);
} catch (SQLException | HibernateException e) {
    // 第一步:清理异常状态的旧Session
    Session currentSession = SessionFactoryUtils.getSession(sessionFactory, false);
    if (currentSession != null && currentSession.isOpen()) {
        // 先解绑当前线程绑定的Session资源
        if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
            TransactionSynchronizationManager.unbindResource(sessionFactory);
        }
        // 关闭Session,释放数据库连接
        SessionFactoryUtils.closeSession(currentSession);
    }

    // 第二步:创建并绑定新Session到当前线程
    Session newSession = sessionFactory.openSession();
    TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(newSession));
    
    // 这里可以继续后续的数据库操作,或者抛出异常让上层处理
    throw new BusinessException("操作失败,已重建Session", e);
}
方案二:自定义事务拦截器(全局统一处理)

因为你用的是TransactionProxyFactoryBean做声明式事务,不如把Session的清理和重建逻辑放到事务拦截器的异常回调里,这样所有事务方法的异常都能统一处理:

  1. 先自定义一个继承自TransactionInterceptor的拦截器:
public class SessionRecoveryTransactionInterceptor extends TransactionInterceptor {

    @Override
    protected Object invokeWithinTransaction(Method method, Class<?> targetClass, InvocationCallback invocation) throws Throwable {
        try {
            return super.invokeWithinTransaction(method, targetClass, invocation);
        } catch (Exception e) {
            // 触发异常时清理旧Session
            SessionFactory sessionFactory = getTransactionManager().getSessionFactory();
            Session currentSession = SessionFactoryUtils.getSession(sessionFactory, false);
            
            if (currentSession != null && currentSession.isOpen()) {
                // 强制回滚未提交的事务(如果有的话)
                if (currentSession.getTransaction().isActive()) {
                    currentSession.getTransaction().rollback();
                }
                SessionFactoryUtils.closeSession(currentSession);
            }
            
            // 重建新Session并绑定
            Session newSession = sessionFactory.openSession();
            TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(newSession));
            
            // 继续抛出异常,不影响上层的异常处理逻辑
            throw e;
        }
    }
}
  1. 然后在Spring配置里把TransactionProxyFactoryBean的transactionInterceptor替换成这个自定义的:
<bean id="customTransactionInterceptor" class="com.yourpackage.SessionRecoveryTransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributes">
        <props>
            <prop key="insert*">PROPAGATION_REQUIRED,rollback-for=java.lang.Exception</prop>
            <prop key="update*">PROPAGATION_REQUIRED,rollback-for=java.lang.Exception</prop>
        </props>
    </property>
</bean>

<bean id="yourServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="target" ref="yourService"/>
    <property name="transactionInterceptor" ref="customTransactionInterceptor"/>
</bean>
关键注意事项
  • 一定要确保旧Session关闭前,所有未完成的事务都已回滚,不然会导致数据库连接泄漏或者数据不一致
  • 重建Session后,要保证后续的DAO操作能正确获取到新的Session(Spring的HibernateDaoSupport或者SessionFactory.getCurrentSession()会自动从线程上下文拿,所以没问题)
  • 尽量避免频繁手动重建Session,优先通过合理的事务边界设计(比如把相关操作放到同一个事务里)来减少异常场景的发生

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:21:16