mybatis的二級緩存

二級緩存是namespace級別的緩存。

1. 開啟二級緩存

修改mybatis-config.xml的setting配置

<setting name="cacheEnabled" value="true"/>

修改對應的mapper文件,在namespace下面添加cache的標簽

<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024" />

cache標簽可以配置的屬性

  • eviction 緩存的相關策略

    • FIFO 先進先出的策略
    • LRU 最近最久未使用調出
    • WEAK 弱引用
    • SOFT 軟引用
  • flushInterval 緩存刷新的毫秒數

  • readOnly 是否只讀

    • true 是只讀,返回引用,速度快但是不安全,同時不要求resultType的POJO類實現Serializable
    • false 通過序列化和反序列化返回,速度比上面的慢同時安全,要求resultType的POJO類實現Serializable,否則會報錯
  • size 緩存的大小

  • type 整合第三方緩存的全類名,可以查看github的mybatis項目,上面有各種mybatis整合第三方cache的示例,https://github.com/mybatis
    關鍵就是實現mybatis的cache接口的方法

2. 效果展示

相關的建表語句啥的見上文。

package com.zihao.test;

import com.zihao.mapper.DeptMapper;
import com.zihao.model.Department;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * 二級緩存對于同一namespace的有效
 * 1)<setting name="cacheEnabled" value="true"/> 開啟關閉的是二級緩存
 * 2) mapper文件中寫明 <cache></cache>
 * 3)readOnly=false的時候 class實現序列化接口
 * 4)對象不是同一個對象 readOnly=false的時候,readOnly=true的時候一個對象
 * 5) 細粒度的控制 <select useCache="false"></> 覆蓋上述配置
 * <insert ></> flushCache默認是true, 可以select標簽添加flushCache=true,select這個值默認是false的
 * 讓一級二級緩存都失效
 * 6) sqlSession.clearCache()清除一級緩存,對二級緩存沒影響
 * 7) loadCacheScope 本地緩存作用域,一級緩存SESSION,STATEMENT可以禁用掉1級緩存
 */
public class SecondCacheTest {
    public static void testSecondCacheTest() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

        //3. 關聯mapper文件
        try {
            DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class);
            DeptMapper deptMapper1 = sqlSession1.getMapper(DeptMapper.class);

            Department department = deptMapper.findDepartmentById(1);
            //關掉才會去拿二級緩存
            sqlSession.close();

            Department departmentCached = deptMapper1.findDepartmentById(1);

            System.out.println(department == departmentCached);

        } finally {
            //4. 關閉連接
            sqlSession1.close();
        }
    }

    public static void main(String[] args) throws IOException {
        testSecondCacheTest();
    }
}

日志輸出如下:

DEBUG 06-15 23:37:50,303 Cache Hit Ratio [com.zihao.mapper.DeptMapper]: 0.0  (LoggingCache.java:62) 
DEBUG 06-15 23:37:50,311 ==>  Preparing: select dept_id, dept_name from tbl_dept where dept_id = ?   (BaseJdbcLogger.java:159) 
DEBUG 06-15 23:37:50,352 ==> Parameters: 1(Integer)  (BaseJdbcLogger.java:159) 
DEBUG 06-15 23:37:50,383 <==      Total: 1  (BaseJdbcLogger.java:159) 
DEBUG 06-15 23:37:50,397 Cache Hit Ratio [com.zihao.mapper.DeptMapper]: 0.5  (LoggingCache.java:62) 
false

上面的例子的??點:

  1. 需要關閉一級緩存,才會把一級緩存放到二級緩存,所以sqlSession.close();這句代碼執行后,再通過sqlsession1進行查詢,會使用
    二級緩存。 如果你把這句語句也放在finally語句里的話,二級緩存是沒起作用的。緩存的順序是先檢查二級緩存,然后一級緩存,沒有才去查詢數據庫的。
  2. 雖然只發送了一次sql語句,但是兩次查詢出來的department對象卻是不一樣的,原因是緩存配置的時候設置了readOnly="false"的
    原因,如果readOnly="true", 兩次結果就是一樣的

3. 其他的說明

  • 影響緩存的相關配置
緩存有關的設置 對一級緩存作用 對二級緩存作用
<setting name="cacheEnabled" value="true"/> 沒影響 影響二級緩存的開啟和關閉,默認是true,建議顯式聲明
<select useCache="false"> 沒影響 影響該select的二級緩存
<select flushCache="true"> 刷新緩存緩存失效,這就是為什么insert導致一級緩存失效的原因,insert的默認flushCache="true" 二級緩存失效
sqlSession.clearCache() 清空一級緩存 對二級緩存沒影響
<setting name="loadCacheScope" value=""/> 默認是SESSION,如果改為了STATEMENT的話,一級緩存失效 二級緩存也失效
  • 引用設置的緩存
    可以在namespace中使用如下語句,避免重復設置緩存。
<cache-ref namespace="xxx"/>
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容