一、什么是session
简单的来说,session类比于jdbc中的connection;
二、session的生命周期
三大生命周期,参见:吾的hibernate总结;
三、细说session线程
session由sessionFactory创建
sessionFactory线程安全,
session线程不安全
解决session线程不安全问题
方案一
需要ThreadLocal;
ThreadLocal 是Java中一种较为特殊的线程绑定机制,通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制,ThreadLocal并不是线程本地化的实现,而是线程局部变量。
也就是说每个使用该变量的线程都必须为该变量提供一个副本,每个线程改变该变量的值仅仅是改变该副本的值,而不会影响其他线程的该变量的值,ThreadLocal是隔离多个线程的数据共享,不存在多个线程之间共享资源,因此不再需要对线程同步。
例子
public class HibernateUtil {
public static final SessionFactory sessionFactory;
public static final ThreadLocal session = new ThreadLocal();
//创建 Configuration容器,可以把其理解为一容器,容器的生命周期就是在一个线程中
static{
try{
Configuration configuration=new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}catch (Throwable ex){
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static Session currentSession() throws HibernateException{
Session s = (Session) session.get();
if (s == null)
{
s = sessionFactory.openSession();
session.set(s); //将session装入 Configuration容器
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
if (s != null)
s.close();//清空容器
session.set(null);
}
}
解决方案二
对象的生命周期与本地线程绑定(通过Thread-local传播Session,线程本地化)
¨ 如果把 Hibernate 配置文件的 hibernate.current_session_context_class 属性值设为 thread, Hibernate 就会按照与本地线程绑定的方式来管理 Session
¨ Hibernate 按以下规则把 Session 与本地线程绑定
• 当一个线程(threadA)第一次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法会创建一个新的 Session(sessionA) 对象, 把该对象与 threadA 绑定, 并将 sessionA 返回
• 当 threadA 再次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法将返回 sessionA 对象
• 当 threadA 提交 sessionA 对象关联的事务时, Hibernate 会自动清理 sessionA 对象的缓存, 然后提交事务, 关闭 sessionA 对象. 当 threadA 撤销 sessionA 对象关联的事务时, 也会自动关闭 sessionA 对象
• 若 threadA 再次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法会又创建一个新的 Session(sessionB) 对象, 把该对象与 threadA 绑定, 并将 sessionB 返回
配置:
¨ 在hibernate.cfg.xml文件中增加
<!-- 配置session的线程本地化 threadLocal -->
<property name="current_session_context_class">thread</property>
¨ 不是调用sessionFactory.openSession().而是调用sessionFactory. getCurrentSession().获取session对象.从当前的线程提取session:
• 当前线程如果存在session对象,取出直接使用
• 当前线程如果不存在session对象,获取一个新的session对象和当前的线程绑定