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. 记录--uni-app在不同平台下拨打电话

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 场景 在App中拨打电话是一个比较常见的应用场景,但是我们通过搜索文章,发现,大部分的博文都是uni-app官网的copy, copy u ...

  2. 记录--记一次前端CSS升级

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 目前平台前端使用的是原生CSS+BEM命名,在多人协作的模式下,容易出现样式冲突.为了减少这一类的问题,提升研效,我调研了业界上主流的7种 ...

  3. 舒服了,学习了,踩到一个 Lombok 的坑!

    你好呀,我是歪歪. 踩坑了啊,最近踩了一个 lombok 的坑,有点意思,给你分享一波. 我之前写过一个公共的服务接口,这个接口已经有好几个系统对接并稳定运行了很长一段时间了,长到这个接口都已经交接给 ...

  4. KingbaseES 物化视图与源表的依赖关系

    KingbaseES例程_重建物化视图的源表 概述 数据结构的修改步骤,数据表先删除,然后创建.如果数据表是物化视图的源表,则提示依赖关系. Oracle的实施 创建数据表和物化视图 create t ...

  5. KingbaseES 分区表与 Oracle 分区表对于空值的处理差异

    一.对于null 值处理 1.Oracle 分区字段允许为空,只要存在maxvalue 分区,值就可以插入. SQL> create table t1(id number,data varcha ...

  6. how to install local jar to maven repository

    如何把maven不能引入的依赖安装到本地Repository: 1.比如fastdfs-client-java. <dependency> <groupId>org.csour ...

  7. #矩阵乘法,线段树#CF575A Fibonotci

    题目 分析 \(K\)那么大肯定是矩阵乘法, 带修改可以用线段树单点修改, 转移矩阵类似于斐波那契数列, 这题思维难度不大,细节很多,需要很长时间QWQ 时间复杂度\(O(mlog_2K)\),具体注 ...

  8. OpenHarmony创新赛|赋能直播第四期

     开放原子开源大赛OpenHarmony创新赛进入了中期评审环节,为了解决开发者痛点,本期以三方库移植.MQTT移植案例.开发工具介绍的3节系列技术课程,帮助开发者提升开发效率,为作品的创新能力奠定坚 ...

  9. 一个很好用的ORM库--peewee

    发现一个很好用的 ORM 库 -- peewee 以下为简单示例 from peewee import * db = SqliteDatabase('test.db') # 定义表结构 class P ...

  10. ThinkPHP6.x 使用指南

    PHP 版本:PHP 8.1.0 框架版本:ThinkPHP 6 编辑工具:PHPStorm 2021.3.3 系统环境:Windows 10 0x01 概述 (1)简介 ThinkPHP 框架简称 ...