緩存是 ORM 框架提升查詢性能的關鍵。MyBatis 提供一級緩存(SqlSession 級)與二級緩存(Mapper 級),並支持可插拔第三方緩存(Ehcache、Redis、Caffeine)。本文系統講解兩級緩存原理、配置、失效策略、整合 Ehcache 實現分布式緩存,並分析二級緩存局限性與最佳實踐。

SqlSession 維度,默認開啟,生命週期與 SqlSession 綁定。不同 SqlSession 緩存隔離。Mapper(namespace)維度,默認關閉,需顯式開啟。同一 Mapper 下多個 SqlSession 共享緩存,跨會話生效。
hashCode + sqlId + SQL語句)@Service
@Transactional
public class UserService {
@Autowired UserMapper userMapper;
public User getUser(Long id) {
// 同一事務 = 同一 SqlSession
User u1 = userMapper.selectById(id); // 查數據庫,寫入一級緩存
User u2 = userMapper.selectById(id); // 命中一級緩存
return u2; // u1 == u2 為 true(同一對象引用)
}
}
事務結束 → SqlSession 關閉 → 一級緩存銷毀。跨事務查詢不共享一級緩存。
SqlMapConfig.xml):
<setting name="cacheEnabled" value="true"/>
UserMapper.xml):
<cache/> <!-- 使用默認 PerpetualCache,HashMap 實現 -->
public class User implements Serializable { ... }

SqlSession1 查詢 → 數據寫入內存(一級緩存)SqlSession1.close() → 一級緩存數據刷新至二級緩存區域(按 namespace 劃分)SqlSession2 查詢 → 直接命中二級緩存(反序列化得到副本,u1 != u2)SqlSession 執行增刷改 commit() → 清空該 Mapper namespace 下整個二級緩存區域| 屬性 | 說明 | 默認值 |
|---|---|---|
eviction |
回收策略:LRU/FIFO/SOFT/WEAK | LRU |
flushInterval |
定時刷新間隔(毫秒),0=不定時刷新 | 0 |
size |
最大引用對象數 | 1024 |
readOnly |
true=返回同一實例(高性能,不可修改);false=返回副本(安全) | false |
type |
自定義緩存實現類(如 EhcacheCache) | PerpetualCache |
<select id="selectLatest" resultType="User" useCache="false">
SELECT * FROM user ORDER BY create_time DESC LIMIT 1
</select>
<insert id="insert" flushCache="true"> ... </insert> <!-- 默認 true,提交後刷新緩存 -->
mybatis-ehcache、ehcache、slf4jehcache.xml:
<ehcache>
<diskStore path="D:/ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<property name="timeToIdleSeconds" value="3600"/>
<property name="timeToLiveSeconds" value="3600"/>
<property name="maxEntriesLocalHeap" value="1000"/>
<property name="maxEntriesLocalDisk" value="10000000"/>
<property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
flushInterval 定時自動失效(如 30 分鐘、1 小時)| 局限 | 原因 | 解決方案 |
|---|---|---|
| 多表關聯更新導致髒讀 | 緩存按 namespace 劃分,表 A 更新無法精確失效表 B 相關緩存 | |
| 細粒度緩存失效困難 | Mapper 級緩存粒度粗,單條數據變更導致整個 Mapper 緩存清空 | |
| 分布式一致性 | 默認實現無分布式能力 |
readOnly=true(不可修改場景)提升性能MyBatis 緩存機制設計精妙,但二級緩存非銀彈。理解其原理、邊界與局限,結合業務場景分層緩存,才能構建高性能、一致性可控的數據訪問層。