文章目錄
- 一、MyBatis 緩存機制詳解
- 1. 一級緩存(Local Cache)
- 2. 二級緩存(Global Cache)
- 3. 緩存執行順序
- 二、MyBatis 緩存的優點
- 三、MyBatis 緩存的缺點
- 四、適用場景與最佳實踐
- 總結
MyBatis 提供了完善的緩存機制,用于減少了數據庫訪問次數,提升查詢性能。其緩存體系分為一級緩存(本地緩存)和二級緩存(全局緩存),兩者配合使用形成了 MyBatis 的緩存體系。
一、MyBatis 緩存機制詳解
1. 一級緩存(Local Cache)
- 作用范圍:SqlSession 級別(即同一個數據庫會話內有效)。
- 實現原理:默認開啟,無需配置。MyBatis 在 SqlSession 內部維護一個 HashMap 作為緩存容器,鍵為
CacheKey
(由 SQL 語句、參數、RowBounds、環境等信息生成),值為查詢結果。- 生命周期:與 SqlSession 一致,當 SqlSession 關閉(
close()
)或提交(commit()
)、回滾(rollback()
)時,一級緩存會被清空。- 觸發場景:
- 同一 SqlSession 中,執行相同的查詢(SQL 語句、參數、分頁等完全一致),會直接從緩存獲取結果,不執行 SQL。
- 若 SqlSession 中執行了增刪改操作(
insert
/update
/delete
),MyBatis 會自動清空一級緩存,避免臟數據。
2. 二級緩存(Global Cache)
- 作用范圍:Mapper 接口級別(跨 SqlSession 共享,多個 SqlSession 可共享同一 Mapper 的緩存)。
- 實現原理:默認關閉,需手動開啟。開啟后,MyBatis 會為每個 Mapper 接口創建一個緩存對象(可自定義緩存實現,如 Redis、EhCache 等),查詢結果會先存入一級緩存,當 SqlSession 關閉時,一級緩存的數據會被刷入二級緩存。
- 開啟方式:
- 在 MyBatis 配置文件中開啟全局二級緩存(默認
true
,可省略):
```xml<settings><setting name="cacheEnabled" value="true"/></settings>```
- 在 Mapper 接口或 XML 中聲明使用二級緩存:
- XML 方式:在 Mapper.xml 中添加 `<cache/>` 標簽。- 注解方式:在 Mapper 接口上添加 `@CacheNamespace` 注解。
- 緩存策略:可通過
<cache>
標簽的屬性配置,如eviction
(回收策略,如 LRU、FIFO)、flushInterval
(自動刷新時間)、size
(最大緩存條目)、readOnly
(是否只讀)等。- 觸發清空:當 Mapper 中執行增刪改操作時,MyBatis 會清空該 Mapper 對應的二級緩存。
3. 緩存執行順序
查詢數據時,MyBatis 會按以下順序查找緩存:
二級緩存 → 一級緩存 → 數據庫
- 若二級緩存命中,直接返回結果。
- 若二級緩存未命中,查詢一級緩存,命中則返回。
- 若一級緩存也未命中,執行 SQL 查詢數據庫,結果依次存入一級緩存和二級緩存(當 SqlSession 關閉時)。
二、MyBatis 緩存的優點
- 減少數據庫訪問:緩存命中時無需執行 SQL,降低數據庫壓力,尤其適合高頻查詢、低頻修改的數據(如商品分類、字典表)。
- 提升查詢性能:緩存查詢為內存操作,響應速度遠快于數據庫 IO,可顯著減少接口響應時間。
- 一級緩存自動維護:無需手動配置,默認生效,適合單會話內的重復查詢(如一次請求中多次查詢同一用戶信息)。
- 二級緩存靈活性高:支持自定義緩存實現(如集成 Redis 實現分布式緩存),可根據業務需求配置回收策略、過期時間等。
- 與事務兼容:增刪改操作會自動清空相關緩存,減少臟數據風險(需正確使用)。
三、MyBatis 緩存的缺點
- 一級緩存局限性:
- 僅在 SqlSession 內有效,多會話共享數據需依賴二級緩存。
- 若 SqlSession 未關閉,長時間持有緩存可能導致數據過期(如其他會話修改了數據,當前會話仍使用舊緩存)。
- 二級緩存潛在問題:
- 臟數據風險:多表關聯查詢時,若關聯表的數據在其他 Mapper 中修改,當前 Mapper 的二級緩存可能未同步更新,導致查詢到臟數據。
例如:OrderMapper
緩存了包含用戶信息的訂單數據,若UserMapper
修改了用戶信息,OrderMapper
的緩存仍為舊數據。- 分布式環境不兼容:默認二級緩存為本地內存緩存,分布式系統中多節點緩存無法同步,可能導致數據不一致(需集成 Redis 等分布式緩存解決)。
- 緩存鍵設計復雜:
CacheKey
依賴 SQL、參數、分頁等信息,若查詢條件細微差異(如參數順序不同),會導致緩存不命中,浪費緩存空間。
- 緩存維護成本:
- 需手動配置二級緩存,且需根據業務調整回收策略、過期時間等參數,增加開發成本。
- 對于高頻修改的數據(如庫存、訂單狀態),緩存命中率低,反而可能因緩存更新帶來額外開銷。
- 調試難度增加:緩存的存在可能掩蓋 SQL 性能問題(如慢查詢因緩存命中未暴露),且排查緩存相關的臟數據問題較為復雜。
四、適用場景與最佳實踐
- 適合使用緩存:
- 高頻查詢、低頻修改的數據(如商品類目、地區信息、字典表)。
- 單表查詢或關聯關系簡單的查詢(避免多表關聯導致的緩存不一致)。
- 分布式環境下,建議使用 Redis 等分布式緩存替代默認二級緩存。
- 不適合使用緩存:
- 高頻修改的數據(如庫存、實時銷量)。
- 多表關聯復雜的查詢(難以保證緩存一致性)。
- 數據實時性要求極高的場景(如金融交易數據)。
- 最佳實踐:
- 優先利用一級緩存,避免在 SqlSession 中執行無關操作,減少緩存無效清空。
- 二級緩存按需開啟,對核心 Mapper 單獨配置,避免全局開啟導致的緩存膨脹。
- 多表關聯查詢時,可通過
@CacheNamespaceRef
關聯相關 Mapper,確保緩存同步清空。- 分布式系統中,集成 Redis 作為二級緩存,保證緩存一致性。
總結
MyBatis 緩存機制通過一級緩存和二級緩存的配合,有效提升了查詢性能,但也存在緩存一致性、分布式兼容等問題。實際使用中需根據業務場景合理配置,權衡性能與數據準確性,避免濫用緩存導致的隱性問題。