標準實現
package com.hkwy.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory SESSION_FACTORY = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Configuration 會自動讀取 classpath 下的 hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError("SessionFactory 創建失敗: " + ex);
}
}
public static SessionFactory getSessionFactory() {
return SESSION_FACTORY;
}
/** 獲取新 Session(線程不安全,請求級) */
public static Session openSession() {
return SESSION_FACTORY.openSession();
}
/** 獲取當前線程綁定 Session(需配置 hibernate.current_session_context_class=thread) */
public static Session getCurrentSession() {
return SESSION_FACTORY.getCurrentSession();
}
/** 關閉 SessionFactory(應用關閉時調用) */
public static void shutdown() {
if (SESSION_FACTORY != null) SESSION_FACTORY.close();
}
}
關鍵點解析
- SessionFactory 是線程安全、重量級、應用級單例:構建過程解析映射、構建元數據、準備連接池,極其昂貴,**全局僅一個**。
- Session 是線程不安全、輕量級、請求級:
openSession() 每次創建新 Session,**必須成對 close()**。
- 靜態代碼塊/字段初始化保證類加載時單次構建,避免雙檢鎖等複雜單例寫法。
- 異常處理:構建失敗拋
ExceptionInInitializerError,快速失敗,防止後續 NPE。
- getCurrentSession():配合
hibernate.current_session_context_class=thread 實現「一請求一 Session」自動綁定/清理,Spring 整合時由框架管理,無需手動調用。
使用範例
// 手動管理事務模式(無 Spring)
public void saveUser(User user) {
Session session = HibernateUtil.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.save(user);
tx.commit();
} catch (Exception e) {
if (tx != null) tx.rollback();
throw e;
} finally {
session.close(); // 必須關閉,歸還連接
}
}
避坑指南
- ❌ 每次 DAO 方法 new Configuration().buildSessionFactory() → 連接池耗盡、元數據重複解析、性能災難。
- ❌ Session 靜態字段共享 → 併發數據錯亂、一級緩存污染、連接洩漏。
- ✅ SessionFactory 單例,Session 方法局部變量。
- ✅ 配置連接池(C3P0/HikariCP),
hibernate.cfg.xml 設置 hibernate.connection.pool_size 或專用連接池屬性。
- ✅ 生產環境關閉
hbm2ddl.auto,改用 Flyway/Liquibase 管理遷移腳本。