美文网首页
mybatis的二级缓存

mybatis的二级缓存

作者: 捞月亮的阿汤哥 | 来源:发表于2019-06-16 00:14 被阅读0次

    二级缓存是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"/>
    

    相关文章

      网友评论

          本文标题:mybatis的二级缓存

          本文链接:https://www.haomeiwen.com/subject/jqfwfctx.html