首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Hibernate 事務與併發控制核心指南(上):Session 管理與工作單元

     編輯:Java 程式設計入門

Hibernate 的事務與併發模型直接映射到底層 JDBC/JTA,不添加額外鎖定行為,核心僅提供自動版本控制(樂觀鎖)。理解 Session 生命週期、事務邊界劃分、工作單元模式,是構建高併發、可擴展應用的基石。本文基於 Hibernate 參考文檔核心章節,系統梳理關鍵概念與最佳實踐。

核心架構三層

層級特性生命週期線程安全
Configuration配置元數據、建立 SessionFactory應用啟動時一次性是
SessionFactory重量級、不可變、緩存映射元數據應用存活期內單例是(所有線程共享)
Session輕量級、非線程安全、代表單個工作單元請求/事務範圍內短暫存在否(嚴禁多線程共享)

Session 與事務範圍:session-per-request 模式

最常用、最推薦的模式:一個 HTTP 請求對應一個 Session 與一個資料庫事務。

// 攔截器/Filter 中實現
public void doFilter(request, response, chain) {
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try {
        tx = session.beginTransaction();
        // 綁定 Session 到當前線程(ThreadLocal)
        CurrentSessionContext.bind(session);
        
        chain.doFilter(request, response); // 執行業務邏輯
        
        tx.commit(); // 提交事務、flush 變更
    } catch (Exception e) {
        if (tx != null) tx.rollback();
        throw e;
    } finally {
        CurrentSessionContext.unbind();
        session.close(); // 釋放 JDBC 連線
    }
}

關鍵原則

  • 事務盡可能短:減少資料庫鎖持有時間,提升併發吞吐
  • Session 延遲獲取連線:僅在首次需資料庫操作時取得連線
  • 禁用 auto-commit:Hibernate 預期由應用控制事務邊界
  • ThreadLocal 綁定:讓 DAO/Service 透過 sessionFactory.getCurrentSession() 取得當前 Session

工作單元與反模式

❌ session-per-operation 反模式

// 錯誤:每次 DB 操作開關 Session
public User getUser(Long id) {
    Session s = factory.openSession();
    User u = s.get(User.class, id);
    s.close();
    return u;
}
public void updateUser(User u) {
    Session s = factory.openSession();
    s.update(u);
    s.close();
}

後果:無法保證原子性、大量開關 Session 開銷大、無法利用一級快取、延遲載入失效。

✅ 單一工作單元分組業務操作

業務邏輯應將多個資料庫調用組合為單一原子工作單元,對應一個 Session 與一個事務。

長對話:應用程式事務

Web 應用常見場景:用戶編輯表單 → 多次請求修改草稿 → 最後提交保存。跨請求的資料庫事務不可接受(鎖太久、併發差)。

解決方案:樂觀鎖 + 脫管物件

  • 實體類別加 @Version 欄位(整數或時間戳)
  • 編輯階段:物件處於脫管狀態,Session 已關閉
  • 提交階段:重新關聯 Session(session.merge(detachedObj)),Hibernate 自動檢查版本號,衝突拋 StaleObjectStateException

Session 狀態轉換圖譜

瞬時態 ----save()/persist()----> 持久態 ----close()/evict()----> 脫管態
     ^                                    |                       |
     |                                    v                       |
     |                              修改屬性 (自動 dirty checking) |
     |                                    |                       |
     +----delete() <----------------------+                       |
     |                                    |                       |
     +----load()/get() <------------------+                       |
     |                                    |                       |
     +----merge() <-----------------------+                       |
     |                                    |                       |
     +----update()/saveOrUpdate() <-------+                       |

Open Session in View 模式爭議

將 Session 範圍延伸至 View 渲染階段,解決延遲載入異常。優點:View 可自由導航關聯。缺點:事務過長、資料庫連線佔用久、業務邏輯與視圖耦合。建議:Service 層預先初始化所需關聯(fetch join、@EntityGraph、DTO 組裝),避免在 View 觸發資料庫查詢。

總結:核心守則

  1. Session 非線程安全:請求範圍內使用,ThreadLocal 隔離
  2. 事務邊界業務驅動:Service 層宣告式(@Transactional)或編程式控制
  3. 拒絕 session-per-operation:工作單元分組業務操作
  4. 長對話用樂觀鎖:@Version + 脫管物件合併
  5. 連線資源珍貴:Session 用完即關,歸還連線池

下篇將深入探討非托管環境、JTA 整合(BMT/CMT)、異常處理與連線釋放策略。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved