一級緩存
MyBatis的一緩存其實就是一個SQLSession級別的,意思就是sqlsession只能訪問自己的一級緩存的數據。一級緩存查詢存在於每一個的sqlsession類的實例對象中,當第一次查詢某一個數據時候,sqlsession類的實例對象會將該數據存入到一級緩存。這樣可以在沒有收到改變該數據的請求之前,我們所查詢數據都是從緩存中去獲取的,而不是從數據庫中去取數據,這樣就大大減少數據庫的頻繁查詢,導致效率降低的原因。
MyBatis的一級緩存是默認開啓
一級緩存原理
首先用戶第一次查詢sql時候,sql的查詢結果就會被寫入sqlsession一級緩存中的,這樣用戶第二次查詢時,直接從一級緩存取出數據,而不是數據庫。
如果用戶出現commit操作時,比如增刪改查,這時sqlsession中一級緩存區域就會全部清空。清空之後再次去一級緩存查找不到,就會走數據庫進行查找,然後再次存到緩存中。注意:緩存使用的數據結構也是map的。
二級緩存
二級緩存的範圍就是mapper級別,也就是mapper以命名空間爲單位創建緩存數據結構,也是map結構。二級緩存和 一級緩存一樣的是,二級緩存的多個sqlsession去操作同一個mapper映射的sql語句,然後多個sqlsession可以共用二級緩存這樣的一個思想,它是跨sqlsession的。
MyBatis的二級緩存是默認關閉
二級緩存實戰
# 二級緩存全局開關. 默認 true
mybatis:
configuration:
cache-enabled: true
源碼解讀
package org.apache.ibatis.session;
public class Configuration {
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
// ...
// 當cacheEnabled爲true的時候,底層使用的Executor纔是支持二級緩存的CachingExecutor
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
}
<mapper namespace="com.jaemon.mapper.OrganMapper">
<!-- 開啓 mapper 下的二級緩存 -->
<cache eviction="LRU" flushInterval="30000" />
<!--
flushCache="true": 該語句的執行結果,會清空本地緩存以及二級緩存
useCache="true": 該語句的執行結果,會被緩存到到二級緩存
-->
<select id="queryOrgById" resultType="com.jaemon.domain.dto.OrgDTO" useCache="true">
select id, org_name, org_type
from sys_org
where id = #{id}
</select>
</mapper>
返回的POJO對象需要實現java.io.Serializable的接口。
public class OrgDTO implements Serializable { }
@Service
public class OrganServiceImpl implements IOrganService {
@Autowired
private OrganMapper organMapper;
@Override
public List<OrgDTO> queryOrgById(Long id) {
List<OrgDTO> orgs1 = organMapper.queryOrgById(id);
List<OrgDTO> orgs2 = organMapper.queryOrgById(id);
return orgs1;
}
}
如果需要驗證一級緩存, 可以用一個事務包裹起來, 讓他們處於同一個sqlSession中
@Override
@Transactional(rollbackFor = Exception.class)
public List<OrgDTO> queryOrgById(Long id) {
List<OrgDTO> orgs1 = organMapper.queryOrgById(id);
List<OrgDTO> orgs2 = organMapper.queryOrgById(id);
return orgs1;
}
cache 屬性
- eviction: 代表的是緩存回收策略,目前MyBatis提供以下策略
- LRU: 最近最少使用的,一處最長時間不用的對象。 默認策略
- FIFO: 先進先出,按對象進入緩存的順序來移除他們
- SOFT: 軟引用,移除基於垃圾回收器狀態和軟引用規則的對象
- WEAK: 弱引用,更積極的移除基於垃圾收集器狀態和弱引用規則的對象。這裏採用的是LRU,移除最長時間不用的對形象
- flushInterval: 緩存刷新間隔,單位爲毫秒。 緩存多長時間清空一次,默認不清空。
- size: 引用數目,一個正整數,代表緩存最多可以存儲多少個對象,不宜設置過大。設置過大會導致內存溢出。這裏配置的是1024個對象
- readOnly: 只讀,意味着緩存數據只能讀取而不能修改,這樣設置的好處是我們可以快速讀取緩存,缺點是我們沒有
辦法修改緩存。 默認 false - type: 可以指定自定義緩存,但是該類必須實現 org.apache.ibatis.cache.Cache 接口
cache-ref 標籤
cache只對特定的Namespace使用,即每個namespace使用一個cache實例,如果要多個namespace使用同一個cache實例,則可以使用cache-ref來引用
有的時候可能我們多個不同的Mapper需要共享同一個緩存的,是希望在MapperA中緩存的內容在MapperB中可以直接命中的,這個時候我們就可以考慮使用cache-ref
<!-- MapperA.xml -->
<mapper namespace="com.jaemon.mapper.MapperA">
<cache />
</mapper>
<!-- MapperB.xml -->
<mapper namespace="com.jaemon.mapper.MapperB">
<cache-ref namespace="com.jaemon.mapper.MapperA"/>
</mapper>
<!-- MapperC.xml -->
<mapper namespace="com.jaemon.mapper.MapperC">
<cache />
</mapper>
二級緩存的應用場景
- 對於訪問多的,實時性要求不高的查詢請求,可以採用mybatis二級緩存技術。
- 對於查詢特別耗時的sql請求,且實時性要求不高(如查詢前24小時或前一個月的消費統計)
二級緩存如何應用
通過設置緩存刷新間隔時間flushInterval,由mybatis每隔一段時間自動清空緩存,可以根據數據變化頻率設置刷新間隔,比如設置爲30分鐘、60分鐘、24小時等,根據需求而定。