Hibernate **一級緩存 (Session 級緩存)** 是**強制啟用、不可關閉**的核心機制。理解其生命周期、範圍、清理策略,是解決**實體狀態管理、性能優化、內存洩漏**的關鍵。
Session session = sessionFactory.openSession();
User u1 = (User) session.load(User.class, 1);
User u2 = (User) session.load(User.class, 1);
System.out.println(u1 == u2); // true — 同一 Session 緩存命中
// 1. evict(Object) — 移除特定實體
User u1 = (User) session.load(User.class, 1);
session.evict(u1);
User u2 = (User) session.load(User.class, 1);
System.out.println(u1 == u2); // false — u1 已從緩存移除
// 2. clear() — 清空整個 Session 緩存
User u1 = (User) session.load(User.class, 1);
session.clear();
User u2 = (User) session.load(User.class, 1);
System.out.println(u1 == u2); // false — 緩存全清
// 3. close() / 不同 Session — Session 結束緩存銷毀
Session s1 = sessionFactory.openSession();
User u1 = (User) s1.load(User.class, 1);
s1.close();
Session s2 = sessionFactory.openSession();
User u2 = (User) s2.load(User.class, 1);
System.out.println(u1 == u2); // false — 不同 Session 獨立緩存
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
int count = 0;
for (Entity entity : largeDataset) {
session.save(entity);
if (++count % 100 == 0) { // 每 100 條
session.flush(); // 同步到數據庫
session.clear(); // **關鍵:清理緩存釋放內存**
}
}
tx.commit();
session.close();
核心邏輯:flush() 推送 SQL,clear() 釋放已持久化實體佔用的緩存內存,防止 OOM。
<hibernate-configuration>
<session-factory>
<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
<property name="hibernate.jdbc.batch_versioned_data">true</property> <!-- 5.2+ -->
</session-factory>
</hibernate-configuration>
batch_size:觸發批量 INSERT/UPDATE 的語句數閾值order_inserts/updates:按實體類型/主鍵排序,最大化批次合併rewriteBatchedStatements=true 在 JDBC URL) save() / persist() flush() / commit()
Transient ----------------> Persistent -----------------> Database
^ | ^ |
| | | evict()/clear()/close() |
| v | |
+----------------------- Detached (游離狀態) ----------------+
update() / merge() / lock()
| 陷阱 | 現象 | 原因 | 解決 |
|---|---|---|---|
| 長會話緩存膨脹 | Open Session in View 模式下內存持續增長 | Session 生命周期過長,緩存累積所有加載實體 | 定期 clear();避免在長會話中加載大量只讀數據 |
| 游離實體修改丟失 | Detached 實體修改屬性,重新關聯未持久化 | 未調用 merge()/update() 重新關聯 | 統一使用 merge() 返回新持久實例 |
| 緩存中臟數據干擾 | 數據庫外部修改,緩存未刷新讀到舊值 | 一級緩存不感知外部變更 | session.refresh(entity) 強制重載;或使用二級緩存+失效策略 |
| 批量插入未生效 | 配置 batch_size 但 SQL 未批量 | ID 生成策略不支持 (如 IDENTITY) / 未達閾值 | 改用 SEQUENCE/TABLE 策略;檢查批次大小 |