mybatis 动态sql 源码解析

mybatis 动态sql

测试例子

java程序

image-20190429141657869

xml文件

image-20190429141822905

调试

直接进入到解析select语句的地方

image-20190429142103850

进入

mybatis 动态sql 源码解析_第1张图片

解析xml

进入buildStatementFromContext,依然是交给XMLStatementBuilder解析

核心部分创建SqlSource

image-20190429142510942

交给XMLLanguageDriver后再转到XMLScriptBuilder

先读取xml配置, 读到一个MiedSqlNode中,主要是将xml节点的层次结构。

mybatis 动态sql 源码解析_第2张图片

解析语句第一部分

先解析<#text> SELECT * FROM POST P WHERE id in

比较简单,直接封装成StaticTextSqlNode。

mybatis 动态sql 源码解析_第3张图片

解析Foreach

,

mybatis 动态sql 源码解析_第4张图片

进入ForeacHandler,

  1. 第一步继续对当前标签内部 进行解析
  2. 将内部属性,解析返回封装成 ForEachSqlNode,可以理解为他自己是个ForEachSqlNode
  3. 将它自己(ForEachSqlNode)加入到他的上级中,这部分代码本身是一个递归操作

mybatis 动态sql 源码解析_第5张图片

进入内部标签解析,开始解析foreach内部,第一个元素是一个文本,仅仅含有一个\n换行,所以最后封装成一个StaticTextSqlNode

mybatis 动态sql 源码解析_第6张图片

第二次循环,解析,

根据标签名,选择ifHandler处理

image-20190429144928267

在IfHandler中,与ForeachHanlder相似,有3步

  1. 解析内部元素
  2. 处理自身需要的属性,并封装为IfSqlNode
  3. 将自身加入到父级SqlNode

image-20190429145303964

解析If

内部就是一个逗号,所以处理 就直接封装成一个StaticTextSqlNode

mybatis 动态sql 源码解析_第7张图片

解析 #{item}

比较简单,也是一个StaticTextSqlNode

mybatis 动态sql 源码解析_第8张图片

最后还有一个\n换行(后面继续调试,发现后有个循环)

问题不大,就是一个StaticSqlTextNode

解析完毕 查看MiexedSqlNode节点

是一个树形结构 未包含最后一个换行

image-20190429150549158

if节点展开

mybatis 动态sql 源码解析_第9张图片

解析完毕 封装DynamicSqlSource

明显会封装成DynamicSqlSource

所有内部含有子标签,或者有${}未处理完毕的都是动态sql

mybatis 动态sql 源码解析_第10张图片

封装成MappedStatement

通过一个简单的构建者模式,生成MappedStatement,保存到configuration,这部分代码不截图了,意义不大。

执行sql

mybatis 动态sql 源码解析_第11张图片

直接进入到下图

  1. 先通过id拿到前面通过xml解析封装成的MappedStatement
  2. 封装查询参数
  3. 交给执行器去执行

封装查询参数比较简单

  1. 集合,数组封装成map,key不一样而已
  2. 对象原样返回

mybatis 动态sql 源码解析_第12张图片

正式开始

先交给CacheExecutor执行,先拿取到BoundSql

通过MappedStatement去拿,MappedStatement转sqlSource处理,我们这里的sqlSource是DynamicSqlSource。

image-20190429153338743

进入到DynamicSqlSource

可以看到第一二行代码,进行动态处理。

与StaticSqlSource不同,StaticSqlSource只需要封装一个BoundSql返回即可,因为解析xml阶段就处理完毕了。DynamicSqlSource还需要在执行过程中进行处理。

image-20190429153733567

实例化一个DynamicContext对象

image-20190429154342143

核心第二步开始 对sqlNode树进行操作

rootSqlNode.apply(context);

MiexedSqlNode转交内部结构自己去处理

image-20190429154540095

处理第一个文本节点

SELECT * FROM POST P WHERE id in

这个StaticSqlNode先行处理,比较简单,直接拼接文本

处理foreach节点

对foreach进行处理

mybatis 动态sql 源码解析_第13张图片

在保存对应参数处理中,将参数存储为自身定义的格式,后续进行相应的替换

image-20190429155813718

内部节点继续进行处理

同样通过MixedSqlNode交给具体SqlNode进行处理

第一个换行节点跳过

解析if

image-20190429160723980

因为是第一个节点 test内容是 index!=0所以会返回false,

否则会进入判断内部,继续对内部的节点进行处理。

后续第二次第三次,会进入判断里面,处理的会将 内部的StaticSqlNode节点进行处理。

因为就是一个逗号文本, 所以返回文本逗号。

这里的处理就是逗号分隔,第一个不要逗号。

解析#{item}

交给Foreach节点下的FilteredDynamicContext处理

mybatis 动态sql 源码解析_第14张图片

通过GenerictokenParser去解析,token解析器将对应的标签专成 前面存储的类型。

再拼接到语句后面。

mybatis 动态sql 源码解析_第15张图片

mybatis 动态sql 源码解析_第16张图片

主要先通过FilteredDynamicContext对元素进行封装,封装格式

__frch_{item}_{index} 

PrefixedContext

DynamicContext生成完毕

mybatis 动态sql 源码解析_第17张图片

SqlSourceBuilder解析sql生成StaticSqlSource

和静态解析一样,对#{}占位符转?处理

直接到SimpleExecutor的doQuery方法

先生成statementHandler

前面获取到了再和对应的静态执行一样。

完毕。

总结

后续对静态sql再进行深入研究。

xml解析理解更加深刻了。对于树结构处理,其实就用到了先序遍历。

对他内部的抽象理解更近一步。

你可能感兴趣的:(mybatis,动态sql)