1、mybatis执行入口
前一篇已经分析过SqlSession内的getMapper方法,最终是通过configuration生成了MapperProxy代理类。所有mapper的如果其实是通过MapperProxy代理执行,代码如下
args参数为mapper方法执行调用的参数
实际执行者为MapperMethod类的execute,此文主要分析select执行过程
上图红框的内容第一处为参数的初步解析,我们看下源码处理,实际是通过ParamNameResolver进行初步的映射关系存储,names存储参数名的顺利映射,参数名若有注解Param则为注解内的参数名,否者参数名为方法内的参数名。
getNamedParams方法则将mapper调用的参数和names内的参数映射,方法如下
初步参数解析成为一个map将存储参数名和实际值的映射
二、参数解析执行过程
实际核心执行者为Executor
我们看看BaseExecutor对于query的实现,隐约可以看到缓存的痕迹此处不分析,图中可以看出BoundSql是由MappedStatement获取的下面分析生成过程
BoundSql为sql的详细信息,参数解析则存在未生成BoundSql的方法内,先看看BoundSql的信息下图可以看出,内部有sql信息及详细映射信息
核心生成过程是有sqlSource实现
sqlSource相关的子类信息,主要分析DynamicSqlSource
主要解析由SqlSourceBuilder实现
SqlSourceBuilder源码
由GenericTokenParser类处理#{}内部的参数,将sql语句内的#{}替换成问号,并且生成
相应的ParameterMapping对象,ParameterMapping内容如下
expression为#{}内的内容,closeToken为‘}’,openToken为‘#{’
ParameterMappingTokenHandler处理,将#{}替换成?,然后解析语句内容生成ParameterMapping对象放入parameterMappings中
到此BoundSql的解析过程基本结束。
回到BaseExecutor查看执行过程,先判断有没有缓存有缓存直接返回内容,没有缓存则执行数据库查询操作
最终的执行者为StatementHandler
看看SimpleStatementHandler的具体实现,由Statement实行boundSql内的sql,下图可以看出结果的映射是由ResultSetHandler处理
Statement的参数化则在BaseExecutor内
参数化的详细过程主要在DefaultParameterHandler内的setParameters下面看源码,主要是根据前期解析出来的ParameterMapping集合,从boundSql内取参数赋值,没有的话根据parameterObject是否有处理类判断赋值
三、结果映射执行过程
ResultSetHandler接口处理
结果的主要由DefaultResultSetHandler类处理,该类的mappedStatement及其先关信息都是由Configuration生成
handleResultSet方法中resultHandler为null是使用DefaultResultHandler处理
主要看看handleRowValuesForSimpleResultMap的执行过程
rowValue为处理后映射的结果对象,我们看看getRowValue如何处理
skipRows跳过逻辑分页如果RowBounds设置了offset则会将offset前的结果集忽略掉,曾经遇到过一次分页插件bug就是由于分页对象继承RowBounds设置了offset导致分页结果错误
getRowValue
主要由createResultObject来创建结果对象
由applyAutomaticMappings和applyPropertyMappings来完成对象和结果集的映射
createResultObject中由ResultMap的getType方法取得结果类型生成相应的对象
再由applyPropertyMappings方法完成对象的映射