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