Hibernate常用的核心接口包括:
Configuration、SessionFactory、Session、Transaction、Query、Criteria。
在完成session擷取的過程中,主要涉及Configuration、SessionFactory、Session接口。
Configuration接口:負責配置并啟動Hibernate,建立SessionFactory對象。在Hibernate的啟動過程中,Configuration類的執行個體首先定位映射文檔位置,讀取配置,然後建立SessionFactory對象。
SessionFactory接口:負責初始化Hibernate,并負責建立Session對象。這裡用到了工廠模式,但是SessionFactory并不是輕量級的,因為在一般情況下,一個項目通常隻需要一個SessionFactory就足夠了,當需要操作多個資料庫時,可以定義多個SessionFactory。
Session接口:負責執行被持久化對象的CRUD操作,但是Session對象是非線程安全的。
ThreadLocal類用于在并發環境下避免競争,簡化程式設計的機制,它在并發環境下提供了一個邏輯上全局的通路點,來通路線程本地變量。ThreadLocal的功能非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是每一個線程都可以獨立的改變自己的副本,而不會和其他線程的副本沖突。從線程的角度來看,就好像每一個線程完全擁有該變量。
public class ThreadLocal {
//HashMap存儲ThreadLocal變量,并實作了線程安全
private Map values = Collections.synchronizedMap(new HashMap());
public Object get(){
Thread curThread = Thread.currentThread();
Object obj = values.get(curThread);
if(obj==null&&!values.containsKey(curThread)){
obj = initialValue();
values.put(curThread, obj);
}
return obj;
}
public void set(Object newValue){
values.put(Thread.currentThread(), newValue);
}
public Object initialValue(){
return null;
}
}
SessionFactory在Hibernate中起到了一個緩沖區的作用,它緩沖了Hibernate自動生成的SQL語句和其他的映射資料,還緩沖了一些将來可能要重複利用的資料。首先介紹下Hibernate的傳遞配置屬性的三種方式:
No.1 使用hibernate.cfg.xml:
Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml");
No.2 使用hibernate.properties:
Configuration cfg = new Configuration();
cfg.configure("/hibernate.properties");
cfg.addResource("com/demo/hibernate/beans/User.hbm.xml");
或
Configuration cfg = new Configuration();
cfg.configure("/hibernate.properties");
cfg.addClass(com.demo.hibernate.beans.User.class);
No.3 構造時寫死:
Configuration cfg = new Configuration()
.addClass(com.demo.hibernate.beans.User.class)
.setProperty("hibernate.dialect","org.hibernate.dialect.MySQLInnoDBDialect");
.setProperty("hibernate.connection","java:com/env/jdbc.test");
.setProperty("hibernate.order_updates","true");
我們知道Configuration執行個體是一個啟動期間(sartup-time)的對象,一旦SessionFactory建立完成她就被丢棄。對于SessionFactory來說,它采用了工廠模式,使用者程式從工廠類SessionFactory中取得Session的執行個體,它的設計者的意圖是讓她在整個應用中共享。典型地說,一個項目通常隻需要一個SessionFactory就足夠了。是以,我們可以這樣定義SessionFactory類:
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class HibernateSessionFactory {
private static final Configuration cfg = new Configuration();
private static org.hibernate.SessionFactory sessionFactory;
private static final ThreadLocal threadLocal = new ThreadLocal();
public static Session currentSession() throws HibernateException{
Session session = (Session)threadLocal.get();
if(session == null){
if(sessionFactory == null){
try{
cfg.configure("hibernate.cfg.xml");
sessionFactory = cfg.buildSessionFactory();
}catch(HibernateException e){
System.out.println("Error Creating SessionFacotry.");
e.printStackTrace();
}
}
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
public static void cloaseSession() throws HibernateException{
Session session = (Session)threadLocal.get();
threadLocal.set(null);
if(session != null){
session.close();
}
}
}
總之,ThreadLocal讓一次程式的運作來使用一個Session,而所有的Session都公用一個SessionFacotry,這樣做有3個好處:
讓所有使用者共用一個SessionFactory,避免了重複建立SessionFactory而造成的資源浪費;
為每一個使用者通路都建立一個Session,避免了不同使用者之間的Session沖突;
在每一次程式運作的周期内,共用一個Session,既可以避免資源浪費,有提供了資源的共享,讓一次運作的多個操作共用一個Session資源,為事務的操作也提供了基礎。
是以,HibernateSessionFactory建立的執行個體關系圖如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jMxUjNwQDN5AzNyQDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
整個系統隻有一個Configuration和SessionFactory對象,而不同的使用者通路有不同的SessionA和SessionB。每一個Session在生命期内,都可以進行多個操作,直到線程通路結束。