核心原則同 SQL 優化:索引覆蓋、避免全表掃描、善用連接順序、限制結果集大小。可參考通用 SQL 調優經驗。
hibernate.cfg.xml)| 參數 | 建議 |
|---|---|
hibernate.show_sql | 生產環境**關閉**,避免 I/O 開銷 |
hibernate.jdbc.fetch_size | 依業務特性調整,非越大越好 |
hibernate.jdbc.batch_size | 批次更新/插入時設定(如 20-50) |
hibernate.cache.use_query_cache | 交易系統**建議關閉**;資料變更頻繁、查詢條件重複率低時反而拖累效能 |
| 層級 | 範圍 | 管理方式 | 適用場景 |
|---|---|---|---|
| 資料庫快取 | 資料庫引擎 | DBA 設定 | 最高效、最安全(Oracle 可 CACHE 表) |
| Session (一級) | 單一 Session | Hibernate 自動,可手動 evict/clear | 大量寫入時防止 OOM |
| SessionFactory (二級) | 全域/叢集 | 映射檔 <cache> 設定 | **優化重點**,頻繁讀取、少量更新的資料 |
| 分散式快取 | 叢集 | 需支援叢集的快取提供者 | 叢集環境,關鍵交易系統建議僅仰賴資料庫快取 |
read-only:靜態/歷史資料,最高效能nonstrict-read-write:極少更新,允許髒讀read-write:通用,效能中等transactional:JTA 環境,支援提供者較少Set/List 包裝(預設開啟)| 情境 | 建議 | 理由 |
|---|---|---|
| 大量資料讀取 | ScrollableResults 或 Iterator | 避免一次載入導致 OOM |
| 單筆載入 | load() 優於 get() | load() 使用二級快取;get() 直接查資料庫 |
| 查詢方法選擇 | 視快取情況選 list() 或 iterate() | 見下表詳細比較 |
list() vs iterate() 深度比較| 特性 | list() | iterate() |
|---|---|---|
| 快取利用 | 僅查詢快取 | **可利用二級快取** |
| SQL 產生 | 通常 1 條(無關聯) | N+1 條(N=符合筆數) |
| 記憶體 | 一次載入所有物件 | 逐筆載入,配合 evict 可控制記憶體 |
| 適用場景 | 小結果集、無二級快取 | 大結果集、已有二級快取命中 |
Iterator it = query.iterate();
while (it.hasNext()) {
YourObject obj = (YourObject) it.next();
// 處理 obj
session.evict(obj);
sessionFactory.evict(YourObject.class, obj.getId());
}
參考 Hibernate 文件 19.5. Understanding Collection performance:
Bag:效能最好(允許重複、無序),適合單向一對多Set:需唯一性,適合雙向一對多(inverse="true")List:需順序,維護成本最高Map:鍵值對關聯<version>),短交易高衝突用悲觀鎖。設定 hibernate.jdbc.batch_size 啟用 JDBC 批次。注意:Hibernate 批次刪除/更新仍會先查詢 ID 以維護二級快取,效能提升有限;新版 bulk HQL 可繞過快取但需自行處理快取一致性。
優化是在「效能」與「正確性/安全性」間尋找平衡點。方案應在架構設計期確定,避免後期返工。應用層快取只是錦上添花,**資料庫設計、演算法、高效 SQL、正確 API 選擇**才是根基。