Mybatis源码解析(六):一级缓存和二级缓存的优先级
创始人
2024-02-02 07:09:03

Mybatis源码系列文章

手写源码(了解源码整体流程及重要组件)

Mybatis源码解析(一):环境搭建

Mybatis源码解析(二):全局配置文件的解析

Mybatis源码解析(三):映射配置文件的解析

Mybatis源码解析(四):sql语句及#{}、${}的解析

Mybatis源码解析(五):SqlSession会话的创建

Mybatis源码解析(六):一级缓存和二级缓存的优先级


目录

  • 前言
  • 一、会话对象selectOne方法
  • 二、获取缓存对象key
    • 1、获取BoundSql对象
    • 2、获取缓存的key值
      • 1)CacheKey构造方法
      • 2)更新方法
  • 三、二级缓存的流程
  • 四、一级缓存的流程
  • 总结


前言

  • 之前篇章讲了配置文件的解析与SqlSession的创建,可以说都是在为执行增删改查操作主流程做铺垫
  • 接下来让我们进入SqlSession的selectOne实现方法

在这里插入图片描述


一、会话对象selectOne方法

selectOne方法

  • SqlSession接口有两个实现类:
    • DefaultSqlSessionFactor(通过上一个步骤创建–>Mybatis源码解析(五):SqlSession会话的创建)
    • SqlSessionManager(已弃用)
  • 方法入参:
    • statement:statementId = “namespace.id”
    • parameter:方法参数,填充带?的sql
  • this.selectList:调用同类的方法,参数传递,从这里可以看出,selectOne方法的实现都交给了selectList,获取到只取第一个值
    • 只有一个值,获取返回即可
    • 如果是空,则返回空
    • 如果大于一个,则报错,因为此方法目的是查询唯一的一个值,结果多个
@Override
public  T selectOne(String statement, Object parameter) {// Popular vote was to return null on 0 results and throw exception on too many.List list = this.selectList(statement, parameter);if (list.size() == 1) {return list.get(0);} else if (list.size() > 1) {throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());} else {return null;}
}

selectList方法

  • 三个selectList方法依次向下调用
  • 第一个方法添加默认分页对象调用第二个方法
  • 第二个方法添加结果集处理器空对象调用第三个方法
  • 第三个核心方法:
    • 通过statementId获取MappedStatement(由每个标签中的flushCache属性,刷新二级缓存,默认false
    • ms.isUseCache:标签中的flushCache属性功能一样
    • 先从一级缓存localCache中获取,没有则从数据库查询
    @Override
    public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());// 如果该执行器已经关闭,则抛出异常if (closed) {throw new ExecutorException("Executor was closed.");}// 1. 如果配置了flushCacheRequired为true,则会在执行器执行之前就清空本地一级缓存if (queryStack == 0 && ms.isFlushCacheRequired()) {// 1.1. 清空缓存clearLocalCache();}List list;try {// 2. 查询堆栈 + 1queryStack++;// 从一级缓存中获取数据list = resultHandler == null ? (List) localCache.getObject(key) : null;if (list != null) {// 3.1. 已有缓存结果,则处理本地缓存结果输出参数(存储过程)handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);} else {// 3.2. 没有缓存结果,则从数据库查询结果list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}} finally {// 查询堆栈数 -1queryStack--;}if (queryStack == 0) {for (DeferredLoad deferredLoad : deferredLoads) {deferredLoad.load();}// issue #601deferredLoads.clear();if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}return list;
    }
    

    进入queryFromDatabase方法

    • 因为延迟加载的原因,这里一级缓存先添加一个占位符
    • 查询结果以后,移除然后再put
    • 具体的查询数据库操作doQuery方法,下一篇文章专门来讲
    private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {List list;// 1. 首先向本地缓存中存入一个ExecutionPlaceholder的枚举类占位valuelocalCache.putObject(key, EXECUTION_PLACEHOLDER);try {// 2. 执行doQuery方法list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);} finally {// 3. 执行完成移除这个keylocalCache.removeObject(key);}// 4. 查询结果存入缓存中localCache.putObject(key, list);// 5. 如果MappedStatement的类型为CALLABLE,则向localOutputParameterCache缓存中存入value为parameter的缓存if (ms.getStatementType() == StatementType.CALLABLE) {localOutputParameterCache.putObject(key, parameter);}return list;
    }
    

    总结

    • 一级缓存和二级缓存就是一个Map集合对象:
      • key:Cache对象(statementId、分页参数、带?的sql、参数值、环境id)
      • value:数据库查询结果
    • 一级缓存默认开启,二级缓存需要添加 标签开启
    • 都开启情况下:先从二级缓存获取,没有则从一级缓存获取,还没有则查询数据库(查询结果后先添加到一级缓存,再添加到二级缓存)

相关内容

热门资讯

应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...