核心問題
SessionFactory:線程安全,應用級單例
Session:非線程安全,請求級對象,多線程共享會導致數據混亂
通用解決方案:ThreadLocal 隔離
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static final ThreadLocal threadLocal = new ThreadLocal<>();
public static Session currentSession() {
Session s = threadLocal.get();
if (s == null) {
s = sessionFactory.openSession();
threadLocal.set(s);
}
return s;
}
public static void closeSession() {
Session s = threadLocal.get();
if (s != null) {
s.close();
}
threadLocal.remove(); // 防止內存洩漏
}
private static SessionFactory buildSessionFactory() {
try {
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
}
使用模式
Session session = HibernateUtil.currentSession();
User user = (User) session.get(User.class, 1);
System.out.println(user.getName());
HibernateUtil.closeSession();
Web 環境深度集成:Filter 管理事務邊界
public class HibernateSessionFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(req, resp); // 處理請求
HibernateSessionUtil.commitTransaction(); // 提交
} catch (Exception e) {
HibernateSessionUtil.rollbackTransaction(); // 回滾
throw new ServletException(e);
} finally {
HibernateSessionUtil.closeSession(); // 關閉 Session
}
}
}
事務工具類完整實現
public class HibernateSessionUtil {
private static final ThreadLocal sessionTL = new ThreadLocal<>();
private static final ThreadLocal txTL = new ThreadLocal<>();
public static Session currentSession() { /* 同 HibernateUtil */ }
public static void closeSession() { /* 同 HibernateUtil */ }
public static void beginTransaction() {
Transaction tx = txTL.get();
if (tx == null) {
tx = currentSession().beginTransaction();
txTL.set(tx);
}
}
public static void commitTransaction() {
Transaction tx = txTL.get();
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.commit();
}
txTL.remove();
}
public static void rollbackTransaction() {
Transaction tx = txTL.get();
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.rollback();
}
txTL.remove();
}
}
Web.xml 配置
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>com.example.HibernateSessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
關鍵最佳實踐
- 請求開始:
HibernateSessionUtil.beginTransaction()
- 業務代碼:
HibernateSessionUtil.currentSession() 獲取 Session
- 請求結束:Filter 自動提交/回滾並關閉 Session
- 異常處理:確保 finally 塊關閉資源
- 避免長事務:事務邊界盡量縮小