在多线程环境中安全使用 HibernateSession 是非常重要的,因为 Session 不是线程安全的。如果不正确处理,可能会导致数据不一致、异常或线程冲突。以下是一些关键的原则和最佳实践:

一、每个线程一个 Session(推荐)

最常见的做法是每个线程拥有自己独立的 Session,避免多个线程同时访问同一个 Session。

示例(使用 ThreadLocal):

public class HibernateUtil {
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<>();

    public static Session getSession() {
        Session session = threadLocal.get();
        if (session == null || !session.isOpen()) {
            session = HibernateSessionFactory.getSessionFactory().openSession();
            threadLocal.set(session);
        }
        return session;
    }

    public static void closeSession() {
        Session session = threadLocal.get();
        if (session != null && session.isOpen()) {
            session.close();
        }
        threadLocal.remove();
    }
}

二、不要在多个线程之间共享 Session

Hibernate 的 Session 内部维护了缓存和上下文信息(如一级缓存、事务状态等),这些都不是线程安全的。因此,以下做法是危险的:

// 错误示范:多个线程共用一个 Session
Session sharedSession = sessionFactory.openSession();
Thread t1 = new Thread(() -> {
    sharedSession.get(SomeEntity.class, 1);
});
Thread t2 = new Thread(() -> {
    sharedSession.save(new SomeEntity());
});

三、使用 Open Session in View 模式时要注意线程隔离

在 Web 应用中,Open Session in View 模式常用于延迟加载。要确保一个请求(通常对应一个线程)绑定一个 Session,并在请求结束时关闭它。

四、使用事务管理器统一控制 Session 生命周期

Spring 等框架中,可以使用声明式事务管理(如 @Transactional 注解)自动绑定 Session 到当前线程。这样可以不手动处理 Session 的打开和关闭。

五、使用 Hibernate 的 StatelessSession(可选)

如果确实需要在多线程环境中共享数据访问逻辑,并且不需要 Hibernate 的缓存、事务管理等特性,可以考虑 StatelessSession,它是线程安全的,但功能较少(没有一级缓存、关联管理、延迟加载等):

StatelessSession statelessSession = sessionFactory.openStatelessSession();

总结:

使用方式是否线程安全适用场景
Session❌ 不线程安全每线程独立使用
ThreadLocal + Session✅ 安全多线程中分离 Session
StatelessSession✅ 安全高性能、无缓存场景
Spring @Transactional✅ 安全Web 应用中推荐做法