Mybatis源码解析(六):缓存执行器操作流程
创始人
2024-02-03 09:25:48
0

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:数据库查询结果
    • 一级缓存默认开启,二级缓存需要添加 标签开启
    • 都开启情况下:先从二级缓存获取,没有则从一级缓存获取,还没有则查询数据库(查询结果后先添加到一级缓存,再添加到二级缓存)

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...