Hibernate 會話工廠(SessionFactory)
1. 前言
Hibernate 的核心價值觀是:開發者們!做你們應該做的。臟的、累的、沒技術含義的由本尊來做。
本節課和大家一起好好的聊聊 Hibernate 的核心組件之一:會話工廠(SessionFactory)。
通過本節課,你將學習到:
- 會話工廠的設計要求;
- 會話工廠的核心功能。
2. 會話工廠的作用
原生 Jdbc 開發如同自己炒菜做飯,需經手買菜、洗菜、做菜…… 一系列過程。
基于 Hibernate 框架開發類似找一家餐館就餐,只需要坐在那里,訂一份菜單,稍等便會有色相味俱全的菜品出現在面前。
餐館并沒有省略買菜、洗菜、做菜一系操作,對于顧客而言,這些由餐館內部工作人員完成。
Hibernate 框架與此類似,原生 JDBC 開發的過程中一系列的標準流程一樣也不能少,只是由內部組件替代完成。
可把餐館當成一個出品菜肴的工廠,為就餐者承擔起一系列臟活、累活……
Hibernate 提供了一個 SessionFactory(會話工廠)對象,任勞任怨地為開發者承擔起 Jdbc 開發流程中底層的繁瑣事務操作。
2.1 概括會話工廠(SessionFactory)的功能
- 為開發者屏蔽創建會話對象(session)時的一系列繁瑣事宜,讓開發者簡單、直接獲取 Session 對象,快速迭代自己的代碼功能;
- 可根據開發者在主配置文件中的配置需求,提供高級輔助功能(如數據庫連接池……);
- 會話工廠可緩存生成的 SQL 語句和 Hibernate 在運行時使用的映射元數據。
SessionFactory 類的設計顧名思議使用到工廠設計模式。經常會在一些框架程序中看到工廠設計模式,工廠設計模式的知名度如此之高,是由它自身的優勢決定的:
- 工廠對象替開發者完成創建對象的細枝末節,讓開發者只需專注于如何運用對象;
- 工廠對象內部可提供創建對象的優化方案,避免因開發者隨意創建對象所帶來的內存消耗。
古人打獵,需要用一周時間打磨工具,用一天時間捕捉獵物。現代人打獵前,可以去商店買一把獵槍,然后盡情享受打獵過程(保護野生動物,禁止打獵!)。
工廠設計模式對開發者說:享受開發吧!少年……
SessionFactory 從功能來講似乎簡單明了,創建 Session(其實這把獵槍不簡單)。
2.2 會話工廠的使用細節
使用細節需要開發者了解:
- SessionFactory 可看成對某一個具體數據庫系統的抽象映射;
- 項目不涉及多數據源時,整個應用程序只需要一個會話工廠,可在應用初始化時創建;
- 多線程環境下,因 SessionFactory 需要在線程間共享,設計時考慮到了線程安全性問題,內部屬性多使用 final 關鍵字修飾;
- 如果使用 Hibernate 訪問多個數據庫,則需要對每一個數據庫使用一個 SessionFactory。
綜上所述:
- 實用生產級別項目中,建議使用單例設計模式封裝 SessionFactory 的創建,保證其應用程序作用域中的唯一性;
- 盡量不要在封裝類中使用全局實例變量存儲數據,避開線程安全性問題。
3. 單例設計模式封裝會話工廠的創建
測試環境是一個演示、求證過程,測試一次創建一個 SessionFactory 對象并沒有什么不妥。
生產環境則不同,代碼結構上設計如果有缺陷,或者不遵循對象本身的特性需求。產品上線后,可能會因為產品的設計缺陷給客戶造成某種程度上的損失。
報酬拿不到事小,丟失市場信任事大。
使用 HibernateSessionFactory 對象封裝 SessionFactory 的創建:
public class HibernateSessionFactory {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
private static ServiceRegistry serviceRegistry;
//加載類時創建會話工廠對象
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(*configuration*.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
session = (sessionFactory != null) ? sessionFactory.openSession():null;
threadLocal.set(session);
}
return session;
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.close();
}
}
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
}
HibernateSessionFactory 類內有很多代碼值得細細品味,本節課你只需要關注單例設計模式實現要素:
- 構造方法私有化,創建對象的能力由內部決定,阻止外部非法任意創建;
private HibernateSessionFactory() {
}
- SessionFactory 在類的靜態代碼塊內創建;
private static org.hibernate.SessionFactory sessionFactory;
//創建會話工廠,只會執行一次,也就只有一個對象
static {
//省略……
}
- 提供公開方法允許外部調用;
public static org.hibernate.SessionFactory getSessionFactory() {
//直接返回內部創建的會話工廠對象
return sessionFactory;
}
無論外部調用 getSessionFactory()方法多少次,最后創建的都只會有一個 SessionFactory 對象。
HibernateSessionFactory 類其它精華代碼留到下一節課程。
4. 小結
工廠、工廠又見工廠!
工廠設計模式是一種屏蔽底層細節,為開發者創建高質量對象的優秀設計方案。怎么表揚這種設計模式都不為過。
到了本節課程說再見時刻,建議開發者,通過本節課程的學習,不僅要理解、掌握 Hibernate 中會話工廠的使用,更能把工廠模式很好地運用到自己的真實項目中。
既要學會使用 Hibernate,也要掌握其內在核心思想。