2023-06-06  阅读(4)
原文作者:惑边 原文地址:https://blog.csdn.net/my_momo_csdn

核心流程-数据读取阶段

一、核心流程-数据读取阶段

  • Mybatis的核心流程三大阶段是:初始化–>动态代理–>数据读写阶段,本文主要分析数据读取阶段。在完成了第一阶段的配置初始化和第二阶段的动态代理之后,我们获得了一个代理对象来面向接口编程,便捷的访问数据库,按照前一篇文章 21-Mybatis 核心流程02-代理阶段的分析我们知道底层还是会走到sqlsession,数据读取阶段就是通过SqlSession完成SQL解析,参数的映射,SQL的执行,结果的解析映射的这个过程。

二、Executor

2.1 功能

  • Executor是数据读取阶段的关键,从21-Mybatis 核心流程02-代理阶段我们知道,所有的操作最后会走到sqlsession,sqlsession会调用Executor组件来执行数据库操作。比如查询操作会调用Executor的的query方法来执行,更新操作会调用Executor的update方法。从这个角度来说,开发者面对的是Sqlsession接口,而SqlSession内部是通过Executor来做数据库操作的。

2.2 实现

    public enum ExecutorType {
      SIMPLE, REUSE, BATCH
    }
类型 描述
simple 默认;使用PreparedStatement访问数据库,每次访问都创建新的PreparedStatement对象
reuse 使用预编译的PreparedStatement访问数据库,会重用Statement对象
batch 批量执行

三、执行流程分析

  • 21-Mybatis 核心流程02-代理阶段 的第五点执行流程分析中我们调试代码到了sqlSession.selectList方法,实际上是 DefaultSqlSession#selectList()方法,我们从这里开始断点调试。

3.1 DefaultSqlSession#selectList

202306062341201281.png

  • DefaultSqlSession#selectList内部调用Executor组件的query方法

3.2 CachingExecutor#query

202306062341208162.png

202306062341214463.png

  • CachingExecutor采用了装饰器模式实现二级缓存,它实现了Executor接口的全部方法且在内部包装了真正的Execuor实例(BatchExecutor、ReuseExecutor或者SimpleExecutor)。在query方法可以看到在执行真正的查询操作之前会访问二级缓存,如果命中就直接返回了,因此二级缓存优先级比一级缓存高。一级缓存实在Executor的query里面实现,而二级是一个包装了Executor的类来做的,它会在调用Executor的query之前去尝试获取缓存数据。

3.3 Executor#query

  • 在3.2中如果二级缓存没有命中,则会调用真正的Executor实例执行query方法,首先会进入BaseExecutor的query方法,因为BaseExecutor是其他子类的抽象父类,在BaseExecutor的query中会尝试读取一级缓存,如果缓存没有命中则会调用queryFromDatabase访问数据库,queryFromDatabase方法是由不同的子类自行实现的,这是模板模式的体现。

202306062341221964.png

3.4 BaseExecutor#queryFromDatabase

  • queryFromDatabase中会访问一级缓存并做相关的细节处理,比如查询数据库成功之后回写一级缓存等,这里会去调用抽象方法doQuery,走到子类的实现逻辑。

202306062341229475.png

3.5 SimpleExecutor#doQuery

  • SimpleExecutor#doQuery是走数据库查询的入口,前面的2次缓存都没有命中就会执行数据库的查询操作。后面就引出了三大对象了,这里就不详细跟进了,在第四节给出简单的流程,详细可参考三大对象的分析逻辑,链接在参考文章的[1][2][3]。

202306062341239486.png

四、读取阶段数据流

  • 方法栈
    --> SqlSession.selectList 
      --> CachingExecutor#query(二级缓存) 
        --> Executor#query 
          --> BaseExecutor#query(一级缓存) 
            --> BaseExecutor#queryFromDatabase(访问数据库) 
              --> SimpleExecutor#doQuery  
                --> StatementHandler获取Statement
                  --> StatementHandler.parameterize处理参数(内部调用DefaultParameterHandler#setParameters) 
                    --> StatementHandler.query() 
                      --> ResultSetHandler.handleResultSets处理结果集(时机调用DefaultResultSetHandler.handleResultSets)
  • 这个流程本文只分析到SimpleExecutor#doQuery ,后面的流程实际上是由另外三大对象完成的,StatemntHandler执行数据库访问,ParameterHandler处理参数,ResultTypeHandler处理结果集,详细请阅读参考文章的[1][2][3]。

五、参考


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文