总结
这里将总结放到前面的目的就是希望读者可以先了解整个的流程和重要代码的意义,以免在具体看的时候迷失方向
查询流程是mybatis最核心的东西
在这个过程中还是希望读者可以跟随本文打断点亲自看下源码,体会很更深些
SqlSession 初始化过程时序图

查询流程

具体类的含义
Configuration:保存configuration配置文件中所有的配置文件DefaultSqlSessionFactory创建SqlSession的工厂类Executor是执行增删改查等方法最基础的方法,底层执行增删改查还是要调用Executor的类的方法的实现-
MapperMethod存放mappe中rselectdelete update insert标签的解析信息 StatementHandler:处理sql语句预编译,设置参数等相关工作;ParameterHandler:设置预编译参数用的ResultHandler:处理结果集TypeHandler:在整个过程中,进行数据库类型和javaBean类型的映射
简单的运行代码
由于是看源码,这里的只有两个查询方法和非常简单的配置
全局配置文件

mapper 接口

mapper 配置文件

测试类

测试类中的
openSession()处打断点,作为程序的入口
断点走走
执行代理对象的 invoke 方法

45 行,判断若调用的方法是继承自
Object的方法,则直接执行,并将结果返回若执行接口自定义的方法,则不直接执行
invoke方法52行从缓冲中获取要执行的方法的
mapper配置文件解析的信息接下来进入52行获取
MapperMethod,该方法就在当前方法下面
获取 MapperMethod

57行从缓存中获取 获取
select标签解析信息若缓存中没有 对应的
select标签解析的MapperMethod则创建MapperMethod接下来进入59 行看看创建
MapperMethod都做了哪些事情
1、创建 MapperMethod

48行创建
SqlCommand对象,SqlCommand是MapperMethod的静态内部类 49行创建MethodSignature对象,MethodSignature是MapperMethod的静态内部类
1.1 创建 SqlCommand

进入48行
208 行创建 全类名+方法名,在后面用于在
configuration中获取MapperMethodstatementName 值为
com.mybatis.source.dao.EmployeeMapper.selectEmployeeById211 行从
configuration中的mappedStatements(map) 中获取MappedStatement226 行将
statementName值设置给SqlCommand类中的属性name将
getSqlCommandType赋值给SqlCommand类的type至此,
SqlCommand创建完成
1.2 创建 MethodSignature

至此创建
MapperMethod完成
接下来返获取
MapperMethod中60行将获取到的
MapperMethod放入缓存中 接下来回到invoke方法
调用 MapperMethod 的 execute方法

execute方法判断执行的sql类型是什么当前执行的查询,所以进入70行判断
判断返回的类型是多条还是Map还是游标,由于返回的是单条记录,索引进入else判断
81 行用于分装参数,将参数封装到
map中,接下来进入到改方法中
参数封装 convertArgsToSqlCommandParam
代码这里就不贴出来了,读者可以看看类 ParamNameResolver 的代码将参数封装为 map的逻辑
调用sqlSession.selectOne 方法(重点的查询从这里开始)

77行实际上调用的是查询多个记录,但是最终返回的是一条记录
进入77行
调用 selectList 方法

147行从
configuration中获取MappedStatement148行执行
executor的查询方法接下来进入148行
executor的查询方法图中
wrapCollection(parameter)解释请看延申部分 一
执行 executor 的 query 方法

81行获取
sql的详细信息,详细请看延申部分 二82行创建缓冲的key
83行执行查询,进入83行

96-108行当有缓存是执行,我们现在没有用到缓存,所以直接执行109行 BaseExecutor的查询方法,接下来进入109行

152 行从一级缓存中获取查询结果,但是我们是第一次执行,所以直接执行156行, 从数据库中查询,接下来进入
queryFromDatabase方法

322,326,328行将查询的结果放入到一级缓存中
324行执行
doQuery方法
执行 SimpleExecutor 的 doQuery 方法

这个地方出现了mybatis的四大对象之一
StatementHandler,其实在创建StatementHandler时将另外两大对象(ParameterHandler和ResultSetHandler)也 作为StatementHandler的成员一起创建了,都是调用了Configuration中的对应的创建方法创建的,另外说下executor也是在Configuration创建的。创建
StatementHandler的过程请看延伸部分 三62行预编译参数,其实调用的是
ParameterHandler进行参数预编译,详细请看延伸部分 四。63行调用处理结果集,其实调用的是
ResultSetHandler对结果集进行处理。还需要注意的地方就是每当创建四大对象时就会调用
interceptorChain.pluginAll对其进行拦截处理,这也正是mybatis插件的原理
延申部分
一: wrapCollection(parameter)

如果参数的类型是
Collectionlistarray则按照对应的名字封装
二:boundSql 详细信息截图

sql语句及其参数的解析就是在这里完成的
三:StatementHandler创建过程

当前方法是
configuration中的newStatementHandler方法530行创建
StatementHandler的实现类RoutingStatementHandler531 行调用插件
接下来进入530行

41行判断查询的类型,创建
StatementHandler,由于我们使用的是默认的StatementType为PREPARED,所以直接执行46行接下来进入46行创建
PreparedStatementHandler

40行调用其继承自
BaseStatementHandler的构造方法,接下来进入BaseStatementHandler的构造方法。

69行70行调用configuration中的方法创建
ParameterHandler和ResultSetHandler作为StatementHandler的参数
四: ParameterHandler 进行参数预编译
进入 62行

86 调用
StatementHandler的参数处理方法,接下来进入86行

直接进入

在这里就调用了
parameterHandler的参数处理方法 继续进入

87调用
typeHandler对参数进行预编译

44行获取当前参数对应的
typeHandler对参数进行预编译, 进入45行看看是怎么预编译的

31行,实际上调用的jdbc原生的PreparedStatement 对参数进行预编译