Mybatis学习1-7——Mybatis缓存机制

MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存。

一级缓存(本地缓存)

与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中取,没必要再去查询数据库。一级缓存是sqlSession级别的缓存,默认一直是开启的。

 @Test
    public void testFirstLevelCache() throws IOException {
         SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
         SqlSession sqlSession = sqlSessionFactory.openSession();
         try {
             EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
             List<Employee> employees = mapper.getEmpByLastName("hello");
             for (Employee employee : employees) {
                 System.out.println(employee);
             }

             List<Employee> employees2 = mapper.getEmpByLastName("hello");
             for (Employee employee : employees2) {
                 System.out.println(employee);
             }
         }finally {
             sqlSession.close();
         }
    }

上面例子中,根据名称查询员工,调用两次getEmpByLastName方法,由于sqlsession本地缓存的存在,第二次并没有调用方法去查数据库,而是直接从缓存中获取。
在这里插入图片描述

  • 一级缓存的失效情况
    一级缓存失效需要重新向数据库发出查询。
    1、sqlSession不同
 @Test
    public void testFirstLevelCache() throws IOException {
         SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
         SqlSession sqlSession = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
         try {
             EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
             List<Employee> employees = mapper.getEmpByLastName("hello");
             for (Employee employee : employees) {
                 System.out.println(employee);
             }
             
             EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);
             List<Employee> employees2 = mapper2.getEmpByLastName("hello");
             for (Employee employee : employees2) {
                 System.out.println(employee);
             }
         }finally {
             sqlSession.close();
             sqlSession2.close();
         }
    }

使用不同的sqlSession对象,尽管两次查询是一样的,第二次查询还是会调用方法,执行sql,查询数据库。
在这里插入图片描述
2、sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)
3、sqlSession相同,两个查询之间执行了增删改操作(增删改可能对当前数据有影响,保证数据一致性缓存失效)

@Test
    public void testFirstLevelCache() throws IOException {
         SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
         SqlSession sqlSession = sqlSessionFactory.openSession();
         try {
             EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
             List<Employee> employees = mapper.getEmpByLastName("hello");
             for (Employee employee : employees) {
                 System.out.println(employee);
             }
             mapper.addEmp(new Employee(null, "testCache", "cache", "1"));
             System.out.println("数据添加成功");

             EmployeeMapper mapper2 = sqlSession.getMapper(EmployeeMapper.class);
             List<Employee> employees2 = mapper2.getEmpByLastName("hello");
             for (Employee employee : employees2) {
                 System.out.println(employee);
             }
         }finally {
             sqlSession.close();
         }
    }

相同的sqlSession,在两次相同的查询中间执行增加数据的操作。
在这里插入图片描述
4、sqlSession相同,手动清除了一级缓存

二级缓存(全局缓存)

基于namespace级别的缓存,一个namespace对应一个二级缓存。

  • 工作机制:
    1、一个会话,查询一条数据,这个数据就会被放在当前的一级缓存中。
    2、如果会话关闭,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存
    3、sqlSession即通过EmployeeMapper查询Employee,也通过DepartmentMapper查询Department,不同namespace查出的数据会放在自己对应的缓存中(map)。
  • 使用
    使用步骤:
    1、开启全局二级缓存配置

    cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。
    2、去mapper.xml中配置使用二级缓存

    cache的一些默认规则:
    eviction:缓存回收策略:
    —— LRU – 最近最少使用的:移除最长时间不被使用的对象。
    ——FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    ——SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    —— WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    默认的是 LRU。
    flushInterval:刷新间隔,单位毫秒,默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
    size:引用数目,正整数,代表缓存最多可以存储多少个对象,太大容易导致内存溢出
    readOnly:只读,true/false
    —— true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。mybatis认为所有从缓存中获取的数据都是只读操作
    ——false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。
    3、我们的POJO需要实现序列化接口Serializable
    效果:数据会从二级缓存中获取,查出的数据都会被默认先放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中。
 @Test
    public void testSecondLevelCache() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        try {
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);

            List<Employee> employees1 = mapper.getEmpByLastName("hello");
            for (Employee employee : employees1) {
                System.out.println(employee);
            }
            //只有会话关闭后,二级缓存中才能有数据
            sqlSession.close();
            List<Employee> employees2 = mapper2.getEmpByLastName("hello");
            for (Employee employee : employees2) {
                System.out.println(employee);
            }
        }finally {
            sqlSession.close();
            sqlSession2.close();
        }
    }

在这里插入图片描述

和缓存有关的设置以及属性

  • cacheEnabled:默认值true,如果设置为false,二级缓存关闭,一级缓存一直可用。
  • useCache:每个select标签都有useCache = “true”,如果设置为false,二级缓存关闭,一级缓存依然可以使用。
  • flushCache:select语句默认值为false,增删改语句默认flushCache = “true”,增删改执行完后就会清除缓存。测试:在两次相同条件的查询语句中间加入增删改操作,一级缓存和二级缓存都会被清空。
  • sqlSession.clearCache():只是清除当前sqlSession的一级缓存
  • localCacheScope:(本地缓存作用域)MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT(禁用缓存),本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。

缓存的原理

在这里插入图片描述
一级缓存是一次会话范围内,相对于sqlSession,不同的sqlSession有不同的缓存区,范围较小。二级缓存一个namespace范围内,不同的mapper.xml有不同的缓存区,新会话进入会先找二级缓存,如果二级缓存没有数据去找一级缓存,一级缓存也没有数据就去执行sql查询数据库。

第三方缓存整合(ehcache)

1、先导入ehcache的核心包
2、导入ehcache与mybatis的适配包(可从官方网站下载),slf4j日志包。
在这里插入图片描述
3、在mapper.xml中使用自定义缓存

 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值