mybatis map里面传对象_Mybatis源码之MappedStatement

我本来想继续写ParameterHandler,在梳理思路时发现,虽然前面写了几篇关于接口的源码解读,但是对于其中的一些概念还欠缺一下认识,尤其是MappedStatement,它贯穿了SqlSession、Executor、StatementHandler等,但是它究竟是什么、有什么用,没有一个全面的了解。所以我想先把这类内容梳理一下,把基础打牢。开始进入正题……

重新认识MappedStatement

每个MappedStatement对应了我们自定义Mapper接口中的一个方法,它保存了开发人员编写的SQL语句、参数结构、返回值结构、Mybatis对它的处理方式的配置等细节要素,是对一个SQL命令是什么、执行方式的完整定义。可以说,有了它Mybatis就知道如何去调度四大组件顺利的完成用户请求。

MappedStatement保存在Configuration#mappedStatements这个Map类型的对象中,其存储的key为MappedStatement#id,所以MappedStatement的id是不能重复的,这个id是由Mapper接口的完全限定名和方法名称拼接而成,这就导致了我们在同一个Mapper中不能出现重载的接口方法。

按照Mybatis的规范,每个Mapper方法也会对应xml中一个select/insert/update/delete标签,Mybatis为这些标签设计了一些属性,允许我们开发人员修改Mybatis的运行方式或行为。大部分情况下,我们不会关注这些属性,是因为Mybatis为其设计了默认值,方便我们开箱即用。我把MappedStatement类中的主要字段进行了注释,这些字段都可以找到与之对应的标签属性,可参考《XML映射文件》,代码贴在了下面,大家先对MappedStatement有个大概的认识。

 1

MappedStatement是怎么来的?

还是以XML配置方式为例进行分析,简单说下源码查找的过程。Mapper对应的SQL语句定义在xml文件中,顺着源码会发现完成xml解析工作的是XMLMapperBuilder,其中对xml中“select|insert|update|delete”类型元素的解析方法为buildStatementFromContext;buildStatementFromContext使用了XMLStatementBuilder类对statement进行解析,并最终创建了MappedStatement。

所以,XMLStatementBuilder#parseStatementNode方法就是我们分析的重点。但是,在此之前需要有一点准备工作要做。由于MappedStatement最终是由MapperBuilderAssistant构建的,它其中存储了一些Mapper级别的共享信息并应用到MappedStatement中。所以,先来简单了解下它的由来:

 1
  • 代码14行:MapperBuilderAssistant由XMLMapperBuilder的私有构造方法创建,这里传入了全局Configuration对象和xml资源文件路径;

  • 代码24~28行:设置builderAssistant的namespace。这个namespace就是我们在mapper xml中声明的,也就是我们Mapper接口的完全限定名,如com.raysonxin.dao.CompanyDao。

  • 代码30行:开始了声明节点的解析。

好了,下面正是开始XMLStatementBuilder#parseStatementNode的分析了。为了节省篇幅,我直接通过代码注释的方式进行说明了,部分我认为不关键或不常用的内容没有多说

 1    

我们在xml中定义的select等语句就是通过这个parseStatementNode方法解析为MappedStatement的,整体来看比较容易理解,核心就是SqlSource的创建过程,大家可以写个简单的例子一步一步调试看下。

SqlSource是什么,如何创建的?

SqlSource是整个MappedStatement的核心,MappedStatement其他一大堆字段都是为了准确的执行它而定义的。SqlSource是个半成品的sql语句,因为对于其中的动态标签还没静态化,其中的参数也未赋值。正是如此,才为我们后续的调用执行提供了基础,接下来重点看看SqlSource的构建过程。为了先从整体上了解,我画了一个时序图来描述SqlSource的解析、创建过程。

1f71bc764b1026ca7fae15ec8b77c7b1.png
image.png

这个过程涉及三个参与者XMLStatementBuilder、XMLLanguageDriver、XMLScriptBuilder,核心在于XMLScriptBuilder对标签的识别与解析,我们重点看XMLScriptBuilder#parseScriptNode这个方法,如下:

 1    

刚才一直再说SqlNode,那SqlNode到底是什么呢?结合一个例子,我们先简单认识一下它,同样放一张类图(图中并没有放全)来了解其家族。

af7e96368fa90082f02e7d3f46a69dcc.png
image.png
1

对于这个示例中的select标签的sql语句(只看2-7行),mybatis会按照标签完整性(闭合)解析为多个节点,同时根据节点中出现的元素类型创建不同类型的节点(依据是《Document Object Model (DOM) Level 3 Core Specification》中定义的12中类型),比如例子中,纯文本解析为TextSqlNode,if标签解析为IfSqlNode。

但是,我们在编写sql语句时大多数情况是多种类型混合的,所以就有了MixedSqlNode,它以List存储了所有的节点。parseDynamicTags方法的作用就是解析sql语句中的节点类型,并最终生成MixedSqlNode。

 1    

总结一下parseDynamicTags方法的处理过程,parseDynamicTags仅处理类型为CDATA_SECTION_NODE、TEXT_NODE、ELEMENT_NODE的节点。

  • 前两种类型会首先作为TextSqlNode,若节点中没有占位符${},则转为StaticTextSqlNode;若节点中有占位符${},节点类型为TextSqlNode不变,但是会将这条sql设置为dynamic。这会导致后续的参数设置方式不同,引出#{}${}的差别,我们在下一节在说明。

  • 对ELEMENT_NODE节点,会根据节点名称(if、choose等)找到对应的处理器解析为动态节点,处理器有IfHandler、WhereHandler等9种。

所以,回到XMLScriptBuilder#parseScriptNode方法,根据isDynamic的值,会创建不同类型的SqlSource。到目前为止,我们知道创建DynamicSqlSource有两种情况:一是sql节点包含if、choose、where这里动态标签时;二是使用了${}占位符时。其余情况会创建RawSqlSource。

好了,SqlSource的创建过程我们就分析完了,在翻上去看看那张时序图加深一下印象吧。

SqlSource创建完成后,就剩下builderAssistant#addMappedStatement这个过程了,比较简单,大家可以自己查看源码了解一下,我就不废话了。

本文总结

正如文章开头所说,本文的主要目的是打基础,弄清楚是什么,为什么,为以后的怎么做做好铺垫。本文分析了MappedStatement主要字段及作用、Mybatis如何创建MappedStatement、MappedStatement中的SqlSource是什么及创建过程几个问题,虽然写的很啰嗦,但是问题应该是描述的差不多了,希望能对大家的理解有一些帮助。

本文到这里就结束了,希望对您有用,如果觉得有用就点个赞吧,^_^!本人水平有限,如您发现有任何错误或不当之处,欢迎批评指正。也可以关注我的微信公众号:“兮一昂吧”。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值