mybatis 緩存介紹(一級緩存、二級緩存)

一級緩存

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>

775325-20160725222958653-633406641.jpg

 

二級緩存的應用場景

  • 對於訪問多的,實時性要求不高的查詢請求,可以採用mybatis二級緩存技術。
  • 對於查詢特別耗時的sql請求,且實時性要求不高(如查詢前24小時或前一個月的消費統計)

二級緩存如何應用
通過設置緩存刷新間隔時間flushInterval,由mybatis每隔一段時間自動清空緩存,可以根據數據變化頻率設置刷新間隔,比如設置爲30分鐘、60分鐘、24小時等,根據需求而定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章