MyBatis 將資料緩存設計為兩級結構:一級緩存(Local Cache)與二級緩存(Application Cache)。兩者在生命週期、作用範圍及配置方式上存在顯著差異。
SqlSession 同步,一次資料庫會話內有效。Executor 物件內部的 Cache 物件中。SqlSession 內重複查詢相同 SQL 且參數相同時,直接返回緩存結果,避免重複查詢資料庫。SqlSession 共享。cacheEnabled=true。Executor 包裝一層 CachingExecutor。查詢時優先檢查二級緩存,命中則直接返回;未命中則委託真實 Executor 查詢後存入緩存。org.apache.ibatis.cache.Cache 接口)及第三方緩存(如 Memcached、Redis)。MyBatis 生成緩存 Key 的時機在 Executor 階段,而分頁插件與 SQL 生成插件在 StatementHandler 階段執行(晚於 Executor)。這些插件通過重寫 SQL 實現功能,但緩存 Key 卻基於原始 SQL 與原始參數生成,導致實際執行的 SQL 與緩存 Key 不匹配,產生錯誤命中。
核心思路:攔截 Executor.query() 方法,在生成 CacheKey 時融合分頁資訊與重寫後的 SQL。
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {
MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class
})
})
public class CacheInterceptor implements Interceptor { ... }
Executor 目標物件。offset、limit)boundSql.getSql() 為空時重新構建 SQL)pageSqlId 正則匹配),額外加入當前頁碼與頁大小CacheKey 呼叫真實 Executor.query()。private CacheKey createCacheKey(MappedStatement ms, Object parameterObject,
RowBounds rowBounds, BoundSql boundSql) {
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
// 處理動態 SQL 生成場景
if (boundSql.getSql() == null || boundSql.getSql().isEmpty()) {
String newSql = SqlBuilder.buildSelectSql(parameterObject);
cacheKey.update(newSql);
// 更新參數映射...
} else {
cacheKey.update(boundSql.getSql());
}
// 融合參數值
// ...
// 處理分頁參數
if (ms.getId().matches(pageSqlId) && metaObject.hasGetter("page")) {
PageParameter page = (PageParameter) metaObject.getValue("page");
cacheKey.update(page.getCurrentPage());
cacheKey.update(page.getPageSize());
}
return cacheKey;
}
public Object plugin(Object target) {
// 僅包裝 CachingExecutor,避免重複代理
return (target instanceof CachingExecutor) ? Plugin.wrap(target, this) : target;
}
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true"/> 微調淘汰算法、刷新間隔與容量。MyBatis 的兩級緩存機制為查詢效能提供了強有力支撐,但預設實現與分頁、動態 SQL 等插件存在時序衝突。透過自定義攔截器重寫 CacheKey 生成邏輯,融合執行時上下文(分頁參數、重寫後 SQL、實際參數值),可徹底解決緩存錯誤命中問題。實務中應結合業務特性靈活配置緩存策略,並建立監控體系確保緩存層穩定高效運作。