Mybatis源码学习(九):缓存的使用

一、前文回顾

在上一篇文章中我们初步探究了什么是缓存以及在Mybatis中缓存是如何定义的,今天将继续学习Mybatis缓存相关的知识。

二、缓存的表现

Mybatis中既然使用了缓存,我们将测试一下缓存的效果。测试代码如下

public class Application {

    public static void main(String[] args) throws Exception {
        String resource = "mybatis-config.xml";
        //读取mybatis配置文件并获取输入流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        try (SqlSession session = sqlSessionFactory.openSession()) {
            PersonMapper mapper = session.getMapper(PersonMapper.class);
            //先查询一次
            Person person = mapper.selectById(1L);
            System.out.println(person);
            //暂停5秒,然后手动修改数据库里的数据
            Thread.sleep(5000);
            person = mapper.selectById(1L);
            System.out.println(person);
        }
    }
}

思路:先查询一次数据库,然后线程sleep 5秒,利用这5秒手动修改一下数据库,然后再次查询。
原始数据:image.png
修改后的数据:image.png

image.png
从结果中可以看出,我们利用线程Sleep的5秒修改了数据库里的数据,但是前后两次查询出来的结果是一致的。从这里可以说明第二次查询并没有经过数据库。我们可以得出结果第二次查询走的是Mybatis自带的缓存。

三、一级缓存

1、缓存的查询

由于前文中Debug很多次了,所以这里不再一步一步的Debug。直接给出使用缓存部分的代码,来到BaseExecutor类。
image.png
可以看到在query方法中首先会去localCache里里查询是否含有我们要的数据,如果没有才会去数据库查询。(这里的localCache,在上方代码中定义 **protected **PerpetualCache localCache;)接下来我们对这个方法进行Debug。

image.png
第一次查询,localCache并没有任何东西,所以会查询数据库。

image.png
第二次查询:localCache有值,value就是我们要查询的数据 Person{id=1, username=‘yeyanghua’, password=‘654321’} key就比较有意思了-312300504:-769787714:com.cmxy.mapper.PersonMapper.selectById:0:2147483647:select * from t_person where id = ?:1:development 接下来我们分析一下Mybatis是如何创建缓存Key的。

2、缓存Key的生成(了解即可)

缓存的Key生成代码在BaseExecutor中。image.png
image.png
可以看出来Mybatis是通过MapperID+分页参数+绑定的SQL+参数+环境来生成一个key。

3、Mybatis一级缓存

其实上面的就是介绍了Mybatis的一级缓存,MyBatis 在一次会话的表示——一个 SqlSession 对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。
MyBatis 在开启一个数据库会话时,会创建一个新的 SqlSession 对象,SqlSession 对象中会有一个新的 Executor 对象,Executor 对象中持有一个新的 PerpetualCache 对象(Cache 接口的实现类);当会话结束时,SqlSession 对象及其内部的 Executor 对象还有 PerpetualCache 对象也一并释放掉。
如果 SqlSession 调用了 close(),会释放掉一级缓存 PerpetualCache 对象,一级缓存将不可用。
如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象中的数据,但是 SqlSession 对象仍可使用。
SqlSession 中执行任何一个增/删/改操作之后执行事务提交 commit() ,都会清空PerpetualCache 对象的数据,但是 SqlSession 对象可以继续使用。
————————————————
版权声明:本文为CSDN博主「一起努力啊啊啊啊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ChineseSoftware/article/details/122881217

四、二级缓存

1、如何使用二级缓存

上面介绍了一级缓存,一级缓存存在一定的局限性,只能作用于同一个SqlSession,那么是否有一种可以在多个SqlSession中共享的缓存体系呢?还真有,Mybatis为我们提供了二级缓存。
二级缓存由称之为全局缓存,与一级缓存不同的是,二级缓存可以针对多个SqlSession生效,二级缓存默认是开启状态。使用二级缓存的条件
(1)在配置文件里设置开启(非必需,默认开启)
(2)在Mapper中引入二级缓存,使用cache标签(必须)
(3)在select标签中使用 useCache属性(非必需)
(4)事务需要提交(必须!否则不会走二级缓存)

2、源码分析

下面我来详细分析一下Mybatis的二级缓存,我们知道缓存是在查询之前的操作,所以二级缓存也一定是作用于查询之前。而在Mybatis中使用Executor来执行相关的操作,所以我们以Executor为切入点
image.png
可以看出Executor有一个名为CachingExecutor的实现类,从名字中就容易推断出该实现是一个和缓存相关的Executor。我们以Query(查询)方法为例,可以看到这里确实是用到了缓存。
image.png
源码分析:
1、首先Mybatis会从MappedStatment中获取缓存对象,由于默认开启了缓存所以下面的cache不为空。
2、接着会判断是否需要刷新缓存(比如增删改操作就需要刷新缓存,当然我们也可以手动设置需要刷新缓存,在mapper.xml文件里配置)
3、接着尝试从缓存中获取本次要查询的数据,如果存在则返回否则查询数据

五、总结

今天的文内容也比较简单。我们了解了Mybatis中的一级、二级缓存,下一篇文章我们将继续学习Mybatis的二级缓存,将深入解析二级缓存。希望对你有所帮助~

未完待续

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值