三大核心狀態
Hibernate 持久化對象在 Session 管理下經歷三種狀態,理解狀態轉換是掌握 Hibernate 的關鍵:
| 狀態 | 英文 | 特徵 | 典型場景 |
| 瞬時態 | Transient | 新創建、無 ID、未關聯 Session、非持久化 | new User() |
| 持久態 | Persistent | 關聯 Session、有 ID、納入一級緩存、事務提交自動同步 DB | session.save()、get()、load() |
| 游離態 | Detached | 曾持久化、Session 關閉/清理/evict、有 ID、非緩存管理 | session.close()、evict()、clear() |
狀態轉換圖譜
Transient (new)
│ save()/persist()
▼
Persistent (get/load/save) ◄── update()/saveOrUpdate() ──► Detached (close/evict)
│ delete() │ │
▼ ▼ ▼
Removed (DB deleted) Synced to DB Re-attached
核心 API 與狀態流轉實戰
1. 瞬時態 → 持久態
// save():立即生成 INSERT,返回生成的 ID
User user = new User("張三", "123");
Serializable id = session.save(user); // 狀態:Persistent
// persist():JPA 標準,可能延遲 INSERT(事務提交時)
session.persist(user);
2. 持久態 → 數據庫同步(自動髒檢查)
User user = session.get(User.class, 1L); // Persistent
user.setName("李四"); // 修改屬性
// 無需調用 update(),事務提交時 Hibernate 自動檢測變化並發送 UPDATE
tx.commit();
3. get() vs load() 關鍵差異
| 特性 | get() | load() |
| 加載策略 | 立即查詢(無延遲) | 支持延遲加載(返回代理對象) |
| 無數據時 | 返回 null | 拋出 ObjectNotFoundException |
| 返回類型 | 實體對象 | 代理對象(CGLIB)或實體 |
| 性能 | 確定需要數據時使用 | 僅需關聯引用(如設置外鍵)時使用 |
// get() 示例
User u1 = session.get(User.class, 1L); // 立即 SELECT
if (u1 != null) System.out.println(u1.getName());
// load() 示例
User u2 = session.load(User.class, 1L); // 不查詢,返回代理
System.out.println(u2.getName()); // 首次訪問屬性時才發送 SELECT
4. 持久態 → 游離態
session.close(); // 所有關聯對象變為 Detached
session.evict(user); // 指定對象變為 Detached
session.clear(); // 清空一級緩存,所有變為 Detached
5. 游離態 → 持久態(重新關聯)
| 方法 | 行為 | 適用場景 |
| update() | 強制 UPDATE,假設數據已修改 | 確定對象已更改,需同步到 DB |
| saveOrUpdate() | 根據 ID 判斷:無 ID → save;有 ID → update | 不確定對象狀態,通用保存 |
| merge() | 複製狀態到持久態對象,返回新實例 | JPA 標準,避免非線程安全問題 |
| lock() | 僅重新關聯,不觸發 UPDATE(配合 LockMode) | 只需重新納入管理,不修改數據 |
// 典型場景:Web 表單提交,對象來自 Session 外部(Detached)
User formUser = ...; // 前端綁定對象,有 ID
session.update(formUser); // 或 saveOrUpdate(formUser)
tx.commit();
6. 刪除操作
// 必須先處於 Persistent 狀態
User user = session.get(User.class, 1L); // 或 load()
session.delete(user); // 發送 DELETE
tx.commit();
一級緩存與髒檢查機制
- 一級緩存:Session 級別,不可禁用,key = 類名 + ID,保證同一 Session 內唯一實例
- 髒檢查:事務提交前,遍歷緩存對比快照,僅對修改字段生成 UPDATE
- flush():手動觸發同步(默認 commit 前自動 flush)
常見陷阱與最佳實踐
| 陷阱 | 後果 | 解決方案 |
| Detached 對象關聯 Persistent 對象 | TransientObjectException | 先 save/merge 關聯對象,再操作主對象 |
| load() 後 Session 關閉再訪問屬性 | LazyInitializationException | 在 Session 內初始化(Hibernate.initialize()),或啟用 Open Session In View |
| 大量數據未分批 flush/clear | OOM / 一級緩存膨脹 | 批量處理:每 20-50 條 flush() + clear() |
| merge() 返回值忽略 | 繼續操作舊 Detached 對象 | 使用 User managed = session.merge(detachedUser) 後續操作 managed |
總結
Hibernate 三大狀態(Transient、Persistent、Detached)與轉換 API(save/get/load/update/merge/delete/evict/clear)構成核心編程模型。關鍵原則:持久態自動同步、游離態需重新關聯、load() 延遲加載需在 Session 內完成、批量操作必須分批清理緩存。深度理解狀態機制,是寫出高性能、無 Bug Hibernate 代碼的基石。