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

Hibernate 核心機制深度解析:實體三態、一級緩存、快照、關聯映射全攻略

     編輯:Java 綜合教學

Hibernate 進階核心:實體狀態流轉、一級緩存/快照機制、一對多/多對多映射實戰

本文系統講解 Hibernate 3 核心機制:持久化實體三種狀態(瞬時/持久/脫管)與轉換規則、Session 一級緩存與快照自動更新原理、get/load 差異、級聯與外鍵維護配置、一對多與多對多雙向關聯映射最佳實踐。

一、持久化實體三態與轉換

狀態特徵OIDSession 關聯資料庫記錄
瞬時態new 建立,未關聯 Session無否無
持久態受 Session 管理,在緩存中有是有(提交前可能無)
脫管態Session 關閉/清除後有否有

狀態轉換關鍵方法

  • 瞬時 → 持久:save()、saveOrUpdate()、persist()
  • 持久 → 脫管:close()、evict()、clear()
  • 脫管 → 持久:update()、saveOrUpdate()、lock()、merge()
  • 持久 → 瞬時:delete()(資料庫記錄刪除)
  • 脫管 → 瞬時:設 id=null 或手動刪除資料庫記錄

核心原則:Hibernate 僅識別 OID。同一 OID 在同一 Session 內只能存在一個持久實例。

二、Session 一級緩存(Session Cache)

本質

Session 內部維護 Map<EntityKey, Object> 等集合,**生命週期 = Session 生命週期**。所有持久態物件自動放入緩存。

作用驗證

// 同一 Session 多次 get 同一 OID
Customer c1 = session.get(Customer.class, 1); // 發 SQL
Customer c2 = session.get(Customer.class, 1); // 無 SQL,直接返回緩存物件
assert c1 == c2; // 同一實例

跨 Session 無效:Session 關閉,緩存銷毀;新 Session 必須重查資料庫。

三、快照機制與自動更新

概念

快照 = 物件載入時的狀態副本(資料庫映射)。**緩存物件被修改 → 緩存 ≠ 快照 → flush 時自動發 UPDATE 同步資料庫**。

flush 觸發時機

  1. transaction.commit()(先 flush 再 commit)
  2. 手動 session.flush()
  3. 執行 HQL/QL/Criteria 查詢(get/load 除外):為保證查詢結果反映最新狀態,先 flush 再查。

get/load 特殊行為

  • 優先走緩存,即使緩存已修改(≠ 快照),也不 flush,直接返回緩存物件**。
  • get:立即查詢,無記錄返回 null。
  • load:延遲載入(代理物件),僅存取 id 不查詢;存取其他屬性才查詢。無記錄拋 ObjectNotFoundException。

緩存操作 API

四、一對多雙向關聯映射(Customer ↔ Order)

表結構

  • t_customer (id PK, name)
  • t_order (id PK, name, cid FK → t_customer.id)

映射檔關鍵配置

<!-- Order.hbm.xml 多方 -->
<many-to-one name="customer" class="Customer" column="cid"/>

<!-- Customer.hbm.xml 一方 -->
<set name="orders" inverse="true" cascade="save-update,delete">
  <key column="cid"/>
  <one-to-many class="Order"/>
</set>

關鍵屬性解析

  • inverse="true":一方放棄外鍵維護權,**由多方(Order)負責維護 cid**,避免雙方各發一條 UPDATE(多餘 SQL)。**生產環境強烈建議一方設 true**。
  • cascade="save-update,delete":一方操作級聯到多方。save-update 允許持久態關聯瞬時/脫管物件自動 save/update;delete 刪除一方時級聯刪除多方(**被刪物件必須是持久態**)。
  • 雙向建立關聯**:customer.getOrders().add(order); order.setCustomer(customer); 兩邊皆需設定,否則記憶體模型不一致。

級聯刪除陷阱

// 錯誤:脫管態刪除,級聯失效,僅置空外鍵
Customer c = new Customer(); c.setId(1);
session.delete(c); 

// 正確:持久態刪除,級聯生效
Customer c = session.get(Customer.class, 1);
session.delete(c); // 訂單同步刪除

五、多對多雙向關聯映射(Student ↔ Course)

表結構

  • t_student (id PK, name)
  • t_course (id PK, name)
  • t_s_c (sid FK, cid FK, 聯合 PK)

映射檔關鍵配置

<!-- Student.hbm.xml -->
<set name="courses" table="t_s_c" inverse="true" cascade="save-update">
  <key column="sid"/>
  <many-to-many class="Course" column="cid"/>
</set>

<!-- Course.hbm.xml -->
<set name="students" table="t_s_c">
  <key column="cid"/>
  <many-to-many class="Student" column="sid"/>
</set>

最佳實踐

  • 不建議配置 delete 級聯**:刪除學生不應刪除課程,否則雙向級聯會清空關聯表甚至級聯刪除另一方實體,造成數據災難。
  • 一方設 inverse="true":由另一方維護中間表,避免重複 INSERT/DELETE。
  • 建立關聯只需單邊操作**:student.getCourses().add(course); 即可(配合 cascade 的一方)。
  • 解除關聯**:student.getCourses().remove(course); → flush 時自動 DELETE 中間表記錄。
  • 修改關聯**:Hibernate 無法對中間表 UPDATE,**只能先 remove 再 add**(先解除舊關聯再建立新關聯)。

六、範式設計與建表規範回顧

  • 1NF:欄位原子性
  • 2NF:有主鍵,非主鍵完全依賴主鍵
  • 3NF:非主鍵不傳遞依賴(僅依賴主鍵)
  • 一對多:多方表加外鍵
  • 多對多:產生關聯表,雙外鍵聯合主鍵
掌握三態轉換、緩存/快照機制、inverse/cascade 語義,是駕馭 Hibernate 高效開發、避免效能與數據一致性陷阱的關鍵。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法作用狀態變化
flush()同步緩存→資料庫持久態維持
clear()清空整個緩存所有持久→脫管
evict(obj)清除指定物件該物件持久→脫管
refresh(obj)資料庫覆蓋緩存持久態維持,修改丟失