一、什麼是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對象和當前的線程綁定