MyBatis源码之MyBatis中SQL语句执行过程

SQL执行入口

我们在使用MyBatis编程时有两种方式:

方式一代码如下:

SqlSession sqlSession = sqlSessionFactory.openSession();
List<Student> studentList = sqlSession.selectList("com.sjdwz.dao.StudentMapper.findAll");

方式二代码如下:

SqlSession sqlSession = sqlSessionFactory.openSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = studentMapper.findAll();

方式一入口分析

方式一调用的是SqlSession接口的selectList方法:

执行的是DefaultSqlSession中的实现

经过多次重载后,调用的是此方法:

MappedStatement封装的是我们的SQL语句;

方法内部执行的是executor的query方法。

方法二入口分析

方法二调用的是SqlSession接口的getMapper(Class type)方法:

我们实际调用的是DefaultSqlSession实现类中的方法:

此方法内部又调用了

 configuration.<T>getMapper(type, this);

最后调用了:

return mapperProxyFactory.newInstance(sqlSession);

通过工厂创建了接口的代理对象。

Mapper接口动态代理

上面讲到会通过

 mapperProxyFactory.newInstance(sqlSession);

来创建动态代理类;

那创建动态代理类会执行哪些方法呢?

可以看到有MapperProxy这个类,实际上都会执行MapperProxy类中的invoke方法。

invoke方法会先判断方法是不是Object的方法,如果是,就直接调用;否则会执行cachedInvoker()方法

cachedInvoker()的作用是获取缓存中MapperMethodInvoker,如果没有则创建一个,而MapperMethodInvoker内部封装了MethodHandler。

当cacheInvoker返回了PalinMethodInvoker实例之后,紧接着调用了这个实例的PlainMethodInvoker#invoke方法

然后就调用了execute()方法

里面调用了sqlSession的方法。

方法的调用关系如下:

MapperProxy#invoke()//代理对象执行的方法,代理后所有Mapper的方法调用时,都会调用这个invoke方法
MapperProxy#cachedInvoker()//代理对象里的Method也是对象,为了避免频繁new对象,在这里给Method对象加缓存
methodCache#computeIfAbsent()//从缓存中取Method对象,取不到创建之后加入缓存
//PainMethodInvoker是MapperProxy的内部类
PlainMethodInvoker#invoke()//执行方法,所有代理对象的方法都会执行同一个。代理对象本质是方法的拦截器!
MapperMethod#execute()//执行方法,最终还是在调用SqlSession接口
SqlSession#insert()
SqlSession#update()
SqlSession#delete()
SqlSession#selectOne()
SqlSession#selectList()

SQL执行流程

查询SQL执行流程

主要步骤:

  1. selectOne/selectList
  2. SQL获取
  3. 参数设置
  4. SQL执行
  5. 封装结果集

调用关系如下:

DefaultSqlSession#selectOne()//执行单记录
DefaultSqlSession#selectList()//查询列表
CachingExecutor#query()
MappedStatement#getBoundSql()//获取SQL语句
CachingExecutor#query()//二级缓存查询
CachingExecutor.delegate = SimplyExecutor//装饰设计模式:Caching的对SimpleExecutor查询加二级缓存装饰
SimplyExecutor#query()
BaseExecutor#query()//子类执行查询直接调用父类方法,一级缓存
BaseExecutor#queryFromDatabase()//缓存没有则去查询数据库,一级缓存
SimplyExecutor#doQuery()//simple执行查询
SimplyExecutor#prepareStatement()//准备查询语句
RoutingStatementHandler#parameterize()//路由delegate=PreparedStatementHandler
PreparedStatementHandler#parameterize()//设置查询参数
DefaultParameterHandler#setParameters()//设置查询参数
RoutingStatementHandler#query()//路由delegate=PreparedStatementHandler
PreparedStatementHandler#query()//执行SQL,封装结果集
PreparedStatement#execute()//执行SQL查询操作
DefaultResultSetHandler#handleResultSets()//封装返回值,将查询结果封装成Object对象

增删改SQL执行流程

主要步骤

  1. insert|update|delete方法分析
  2. SQL获取
  3. 参数设置
  4. SQL执行
  5. 封装结果集

MyBatis中增删改的代码如下:

//DefaultSqlSession
@Override
public int insert(...) {
return update(statement, parameter);
}
@Override
public int update(String statement) {
return update(statement, null);
}
@Override
public int delete(...) {
return update(....);
}

我们发现,增删改最后执行的都是update,这是因为insert、update、delete实际上都是对数据库中数据的改变

执行流程为:

DefaultSqlSession#update()
CachingExecutor#update()//执行更新
flushCacheIfRequired()//执行增删改前,清除对应二级缓存
CachingExecutor.delegate = SimplyExecutor//装饰模式
SimplyExecutor#update()//调用父类模板方法
BaseExecutor#update()//执行更新
BaseExecutor#clearLocalCache()//清除一级缓存,LocalCache
BaseExecutor#doUpdate()//调用子类方法
SimplyExecutor#doUpdate()//simple执行更新
SimplyExecutor#prepareStatement()//准备查询语句
RoutingStatementHandler#parameterize()//delegate=PreparedStatementHandler
PreparedStatementHandler#parameterize()//设置查询参数
DefaultParameterHandler#setParameters()//设置查询参数
RoutingStatementHandler#update()//delegate=PreparedStatementHandler
PreparedStatementHandler#update()
PreparedStatement#execute()//执行SQL,完成增删改查操作
reparedStatement#getUpdateCount()//获取影响行数

图示

最后我们画出执行的流程图如下:

MyBatis源码之MyBatis中SQL语句执行过程的更多相关文章

  1. 转:Oracle中SQL语句执行过程中

    Oracle中SQL语句执行过程中,Oracle内部解析原理如下: 1.当一用户第一次提交一个SQL表达式时,Oracle会将这SQL进行Hard parse,这过程有点像程序编译,检查语法.表名.字 ...

  2. mybatis源码-Mapper解析之SQL 语句节点解析(一条语句对应一个MappedStatement)

    目录 一起学 mybatis 0 <sql> 节点解析 1 解析流程 2 节点解析 2.1 解析流程 2.2 <include> 节点的解析 2.3 Node.ELEMENT_ ...

  3. Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource

    前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(二) 首先了解下sql mapper的动态sql语法 具体的动态sql的 ...

  4. Spring mybatis源码篇章-Mybatis的XML文件加载

    通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-Mybatis主文件加载 前话 前文主要讲解了Mybatis的主文件加载方式,本文则分析不使用主文件加载方式 ...

  5. html5 webDatabase 存储中sql语句执行可嵌套使用

    html5 webDatabase 存储中sql语句执行可嵌套使用,代码如下: *); data.transaction(function(tx){ tx.executeSql("creat ...

  6. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  7. 精尽 MyBatis 源码分析 - MyBatis 初始化(三)之 SQL 初始化(上)

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  8. 精尽MyBatis源码分析 - MyBatis初始化(四)之 SQL 初始化(下)

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  9. 精尽MyBatis源码分析 - MyBatis 的 SQL 执行过程(一)之 Executor

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  10. Mybatis源码解读-SpringBoot中配置加载和Mapper的生成

    本文mybatis-spring-boot探讨在springboot工程中mybatis相关对象的注册与加载. 建议先了解mybatis在spring中的使用和springboot自动装载机制,再看此 ...

随机推荐

  1. LOTO示波器客户应用案例展示

    LOTO示波器客户应用案例展示 LOTO示波器以软件功能为核心,采用独特的积木式可扩展的硬件架构,为多行业的电子电路研发工程师提供高性价比的解决方案.我们初步汇总了一些客户实测的应用案例展示如下: 1 ...

  2. WPF如何封装一个可扩展的Window

    前言 WPF中Window相信大家都很熟悉,有时我们有一些自定义需求默认Window是无法满足的,比如在标题栏上放一些自己东西,这个时候我们就需要写一个自己的Window,实现起来也很简单,只要给Wi ...

  3. Scala 简单分词求和

    1 package chapter07 2 3 object Test17_CommonWordCount { 4 def main(args: Array[String]): Unit = { 5 ...

  4. #轮廓线dp,模型转换#洛谷 3226 [HNOI2012]集合选数

    题目 问有多少个集合 \(S\) 是 \([1,n]\) 的子集, 并且 \(\forall a,b\in S,a|b\),满足 \(\frac{b}{a}\neq \{2,3\}\) 分析 可以发现 ...

  5. OpenHarmony使用ArkUI Inspector分析布局

      本文转载自<#2023 盲盒+码 # OpenHarmony使用ArkUI Inspector分析布局>,作者:zhushangyuan_ OpenHarmony使用ArkUI Ins ...

  6. OpenHarmony Liteos_A内核之iperf3移植心得

    一.iperf3工作原理 iperf3主要的功能是测试基于特定路径的带宽,在客户端和服务器端建立连接(三次握手)后,客户端发送一定大小的数据报并记下发送的时间,或者客户端在一定的时间内发送数据并记下发 ...

  7. 在Centos 8 服务器用tmux多开窗口

    在 CentOS 服务器上使用 tmux 来多开窗口是一个高效的方式.tmux 是一个终端复用器,它允许你在一个终端窗口中打开多个终端会话,还可以在会话之间轻松切换,非常适合长时间运行程序或多任务操作 ...

  8. 十城百校联动!HDC.Together 2023 HarmonyOS学生公开课与千余名校园学子见证鸿蒙力量

      8月6日,HDC.Together2023 HarmonyOS学生公开课在东莞松山湖举办.有来自清华大学.北京大学.哈尔滨工业大学等全国百余所高校,千余名学生开发者齐聚会场,与华为高级技术专家.生 ...

  9. nginx 均衡负载

    前言 在此只介绍一些nginx的简单的负载均衡. 正文 在这篇之前,请看我的nginx反向代理这一篇,是接着上面的例子写的. 我在上个例子中,分别是两个a.html 和 b.html 现在我把他们的名 ...

  10. 安装 php_mongodb.dll的坑

    背景 php_mongodb.dll在这里介绍的是for php,php_mongodb.dll是这个坑,因为php_mongodb.dll前生是php_mongo.dll,而这个东西,它又不更新了, ...