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

Hibernate 鎖機制深度解析:悲觀鎖與樂觀鎖實戰對比

     編輯:Java 相關知識

Hibernate 提供兩種並發控制機制:悲觀鎖依賴資料庫鎖,樂觀鎖基於版本號應用層實現。選型需根據業務並發特性與效能要求權衡。

悲觀鎖

核心邏輯

假設並發衝突高發,讀取即加鎖(SELECT ... FOR UPDATE),阻塞其他事務讀寫,直至提交釋放。

JDBC 實現

SELECT * FROM account WHERE name = 'Erica' FOR UPDATE

Hibernate API

Query query = session.createQuery("FROM Account WHERE name = :name");
query.setParameter("name", "Erica");
query.setLockMode("account", LockMode.UPGRADE);  // 關鍵:查詢前加鎖
Account account = (Account) query.uniqueResult();

鎖模式對照

效能考量

高併發下資料庫鎖競爭激烈,連線佔用久、吞吐率低。適用於:併發低、衝突嚴重、強一致性要求高的核心業務(如扣款、庫存扣減)。

樂觀鎖

核心邏輯

假設衝突稀少,讀取不加鎖,更新時比對版本號。版本匹配 → 更新成功並版本+1;不匹配 → 拋出 StaleObjectStateException,重試或回滾。

資料庫設計

ALTER TABLE account ADD COLUMN version INT DEFAULT 0;

實體類映射

@Entity
@Table(name = "account")
@org.hibernate.annotations.OptimisticLocking(type = OptimisticLockType.VERSION)
public class Account {
    @Version
    @Column(name = "version")
    private int version;
    // ... 其他欄位
}

或 XML 映射:<version name="version" column="VERSION" />

業務流程範例

  1. A 讀取餘額 1000,版本 5
  2. B 讀取餘額 1000,版本 5
  3. A 扣款 500 → 更新餘額 500,版本 6(5→6 成功)
  4. B 扣款 300 → 更新餘額 700,版本 6(5≠6 失敗,拋異常)
  5. B 捕獲異常 → 重讀最新資料 → 重新業務邏輯 → 再次提交

異常處理模式


try {
    session.update(account);
    tx.commit();
} catch (StaleObjectStateException e) {
    // 策略:重讀、合併、提示用戶、自動重試
    session.refresh(account);  // 重新載入最新版本
    // 重新應用業務邏輯...
}

外部系統風險警示

樂觀鎖僅保護本系統內更新。若外部系統(如銀行扣款回調、ERP 同步)繞過 Hibernate 直接更新資料庫,版本號不會遞增,導致髒寫。
對策:資料庫層面觸發器強制版本遞增、或關鍵表強制悲觀鎖、或引入分散式鎖協調。

選型決策表

模式說明資料庫層面
NONE無鎖無
WRITEInsert/Update 自動獲取無
READ讀取自動獲取無
UPGRADEFOR UPDATE有
UPGRADE_NOWAITFOR UPDATE NOWAIT (Oracle)有
維度悲觀鎖樂觀鎖
並發衝突頻率高低
持鎖時間長(含業務邏輯)極短(僅更新瞬間)
資料庫負載高(鎖等待)低
適用場景金融扣款、庫存扣減用戶資料編輯、配置修改
外部系統干擾免疫脆弱
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved