MyBatis框架一级缓存与二级缓存

Posted 一梦先知

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis框架一级缓存与二级缓存相关的知识,希望对你有一定的参考价值。

为了提升查询效率,提高用户体验,MyBatis提供了数据缓存支持,依据数据缓存的有效范围默认定义了一级缓存和二级缓存

一级缓存

1、该级缓存默认开启,不能关闭;

2、该级缓存为SqlSession级别的缓存,也称为本地缓存;

3、以下4种情况将会导致该级缓存失效:

  a、在不同SqlSession中查询数据;

public class Test {

    public static void main(String[] args) {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);//为true自动提交,默认false开启事务需要手动commit
            
            IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            List<UserInfo>list = userInfoDao.select();
            System.out.println(list.size());
            list = userInfoDao.select();
            System.out.println(list.size());
            sqlSession.close();
            
            sqlSession = sqlSessionFactory.openSession();
            userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            list = userInfoDao.select();
            System.out.println(list.size());
            sqlSession.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

执行结果:同一个sqlSession中缓存成功,不同的sqlSession缓存失效

 

  b、相同SqlSession中查询数据,但查询条件不同

public class Test {

    public static void main(String[] args) {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);//为true自动提交,默认false开启事务需要手动commit
            
            IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            List<UserInfo>list = userInfoDao.select("%阿%");
            System.out.println(list.size());
            list = userInfoDao.select("%a%");
            System.out.println(list.size());
            sqlSession.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

执行结果:

 

 

  c、相同SqlSession中查询数据,但两次查询之间执行了增删改操作

public class Test {

    public static void main(String[] args) {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);//为true自动提交,默认false开启事务需要手动commit
            
            IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            List<UserInfo>list = userInfoDao.select();
            System.out.println(list.size());
            
            boolean flag = userInfoDao.delete("1");
            System.out.println(flag);
            
            list = userInfoDao.select();
            System.out.println(list.size());

            sqlSession.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

执行结果:

 

 

 

  d、相同SqlSession中查询数据,但第二次查询前,程序调用SqlSession对象clearCache()方法手动清除了一级缓存

public class Test {

    public static void main(String[] args) {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);//为true自动提交,默认false开启事务需要手动commit
            
            IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            List<UserInfo>list = userInfoDao.select();
            System.out.println(list.size());
            
            sqlSession.clearCache();
            
            list = userInfoDao.select();
            System.out.println(list.size());

            sqlSession.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

执行结果:

 

 

二级缓存

1、该级缓默认不开启,但如果使用二级缓存需要在每个XML映射文件中添加<cache></cache>以配置该级缓存(相应实体类要序列化)。二级缓存可以通过在全局配置文件配置setting标签来关闭该级缓存。

​ 如果这样配置的话,很多其他的配置就会被默认进行,如:

  • 映射文件所有的select 语句会被缓存
  • 映射文件的所有的insert、update和delete语句会刷新缓存
  • 缓存会使用默认的Least Recently Used(LRU,最近最少使用原则)的算法来回收缓存空间
  • 根据时间表,比如No Flush Interval,(CNFI,没有刷新间隔),缓存不会以任何时间顺序来刷新
  • 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用
  • 缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以很安全的被调用者修改,不干扰其他调用者或县城所作的潜在修改

可以在开启二级缓存时候,手动配置一些属性

<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>

各个属性意义如下:

  • eviction:缓存回收策略
    - LRU:最少使用原则,移除最长时间不使用的对象
    - FIFO:先进先出原则,按照对象进入缓存顺序进行回收
    - SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
    - WEAK:弱引用,更积极的移除移除基于垃圾回收器状态和弱引用规则的对象
  • flushInterval:刷新时间间隔,单位为毫秒,这里配置的100毫秒。如果不配置,那么只有在进行数据库修改操作才会被动刷新缓存区
  • size:引用额数目,代表缓存最多可以存储的对象个数
  • readOnly:是否只读,如果为true,则所有相同的sql语句返回的是同一个对象(有助于提高性能,但并发操作同一条数据时,可能不安全),如果设置为false,则相同的sql,后面访问的是cache的clone副本。

2、该级缓存为namespace级别的缓存

3、工作机制:通过SqlSession查询数据,这些数据将会放到当前会话的一级缓存中;如果当前会关闭,则一级缓存中的数据会被保存到二级缓存中,此后新的SqlSession将从二级缓存中查找数据;

public class Test {

    public static void main(String[] args) {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);//为true自动提交,默认false开启事务需要手动commit
            
            IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            List<UserInfo>list = userInfoDao.select();
            System.out.println(list.size());
            
            sqlSession.close();
            
            sqlSession = sqlSessionFactory.openSession();
            userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            list = userInfoDao.select();
            System.out.println(list.size());
            sqlSession.close();


        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

执行结果:

 

 

4select标签的useCache属性用于设置是否使用二级缓存;insertupdatedeleteselect标签均有flushCache属性,其中增删改默认true,即sql执行以后,会同时清空一级和二级缓存,查询默认false

public class Test {

    public static void main(String[] args) {
        try {
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);//为true自动提交,默认false开启事务需要手动commit
            
            IUserInfoDao userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            List<UserInfo>list = userInfoDao.select();
            System.out.println(list.size());
            
            sqlSession.close();
                    
            sqlSession = sqlSessionFactory.openSession();
            userInfoDao = sqlSession.getMapper(IUserInfoDao.class);
            boolean flag = userInfoDao.delete("1");//清空二级缓存
            System.out.println(flag);
            
            list = userInfoDao.select();
            System.out.println(list.size());
            sqlSession.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
}

执行结果:

 

 

5、为了提高扩展性,MyBatis定义了Cache缓存接口,可以通过实现该缓存接口自定义二级缓存,jar包下载:https://github.com/mybatis

为了提升查询效率,提高用户体验,MyBatis提供了数据缓存支持,依据数据缓存的有效范围默认定义了一级缓存和二级缓存

以上是关于MyBatis框架一级缓存与二级缓存的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis 一级缓存与二级缓存

mybatis缓存,包含一级缓存与二级缓存,包括ehcache二级缓存

Mybatis一级缓存与二级缓存的区别你知道吗

Mybatis一级缓存与二级缓存的区别你知道吗

MyBatis框架查询缓存-二级缓存原理

Mybatis的一级缓存与二级缓存