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

Hibernate 3 進階特性 (一):悲觀鎖與樂觀鎖並發控制、Lifecycle/Validatable 介面實戰

     編輯:Java 相關知識

多用戶並發訪問同一數據時,必須採取並發控制機制。Hibernate 3 提供悲觀鎖 (資料庫層面) 與樂觀鎖 (應用層面版本號) 兩大策略,並支援 Lifecycle、Validatable 介面實現領域模型自我驗證。本文系統講解並附完整代碼示例。

悲觀鎖:資料庫級獨佔鎖

假設並發衝突頻繁,在讀取/更新時獨佔鎖定記錄直到事務結束。通過 LockMode 指定:

  • LockMode.UPGRADE:SELECT ... FOR UPDATE (標準 SQL)。
  • LockMode.UPGRADE_NOWAIT:Oracle FOR UPDATE NOWAIT,不等待直接報錯。
  • LockMode.READ、WRITE、NONE:Hibernate 內部自動管理 (讀/寫/無鎖)。

使用方式

// Query/Criteria 級別
Query q = session.createQuery("from User u");
q.setLockMode("u", LockMode.UPGRADE);
List users = q.list();

// 單一實體載入/鎖定
User u = (User) session.load(User.class, id, LockMode.UPGRADE);
// 或已載入實體後升級鎖
session.lock(u, LockMode.UPGRADE);

生成 SQL:select ... from user u for update。若資料庫不支援指定模式,Hibernate 自動降級而非拋異常。

樂觀鎖:版本號機制避免長事務鎖定

假設衝突稀少,讀取時攜帶版本號,更新時比對版本號:

  • 版本號相等 → 更新成功,版本號 +1。
  • 版本號過舊 → 拋出 StaleObjectStateException。

實現步驟

  1. 資料表增加 version 欄位:version INT。
  2. 實體類增加 version 屬性:private Integer version; 含 getter/setter。
  3. 映射文件聲明:
    <class name="User" table="user" optimistic-lock="version">
      <id .../>
      <version name="version" column="version" type="java.lang.Integer"/> <!-- 必須在 <id> 之後 -->
      <property .../>
    </class>
    

並發衝突演示

// 用戶 1 載入
Session s1 = sf.openSession(); User u1 = (User) s1.load(User.class, 1);
// 用戶 2 載入同一記錄
Session s2 = sf.openSession(); User u2 = (User) s2.load(User.class, 1);
// 版本號相同 (如 0)

Transaction tx1 = s1.beginTransaction();
u1.setAge(31); tx1.commit();  // 版本號變 1

Transaction tx2 = s2.beginTransaction();
u2.setName("Justin");  // u2 版本號仍 0
tx2.commit();  // 拋出 StaleObjectStateException

異常處理策略:捕獲異常 → 重新載入最新數據 → 合併用戶修改 → 重試提交,或呈現衝突讓用戶決定。

風險提示

樂觀鎖屬應用層邏輯,若繞過 Hibernate 直接更新資料庫 (如批次腳本、外部系統) 未同步版本號,鎖定失效。嚴禁手動修改 version 屬性繞過檢查。

Lifecycle 介面:實體自我管理持久化事件

實體實作 org.hibernate.classic.Lifecycle,Session 操作前自動回調:

public interface Lifecycle {
    boolean onSave(Session s);    // true/異常 → 取消儲存
    boolean onUpdate(Session s);  // true/異常 → 取消更新
    boolean onDelete(Session s);  // true/異常 → 取消刪除
    void onLoad(Session s, Serializable id);
}

適用場景:儲存前自動填充衍生欄位、更新時記錄變更日誌、刪除前檢查引用完整性。

Validatable 介面:持久化前驗證

實體實作 org.hibernate.classic.Validatable:

public interface Validatable {
    void validate() throws ValidationFailure;
}

持久化前 (save/update) 自動調用 validate(),拋出 ValidationFailure 則取消操作。適合領域模型內嵌業務規則驗證 (如金額>0、日期邏輯)。

總結

機制層級適用場景注意事項
悲觀鎖資料庫高衝突、短事務、需強一致性長事務易死鎖、擴展性差
樂觀鎖應用 (版本號)低衝突、長會話、Web 應用首選需防繞過、外部更新同步版本號
Lifecycle實體回調審計、衍生欄位、軟刪除耦合 Hibernate API、慎用
Validatable實體驗證領域不變約束異常類型固定、建議改用 Bean Validation (JSR 303)

現代開發建議:並發控制首選樂觀鎖 (配合 @Version 註解);業務驗證遷移至 Bean Validation;審計等橫切關注點採用 AOP 或事件監聽器 (JPA @EntityListeners),降低領域模型對持久化框架耦合。

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