Spring mybatis源码篇章-动态SQL基础语法以及原理
通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-Mybatis的XML文件加载
前话
前文通过Spring中配置mapperLocations属性来进行对mybatis的XML文件的解析,本文将在前文的基础上简单的来看下Mybatis的使用的基础语法以及解析原理
动态sql语法
具体的动态sql的使用可在官网查看Mybatis 3 | Dynamic SQL
1.if,条件判断
<select id="findActiveBlogWithTitleLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
</select>
与JAVA语意中的条件判断是类似的
2.choose/when/otherwise,类似于if/else语句判断
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
3.trim,多搭配where节点进行SQL语句拼装
<!--prefix/suffix属性均是由prefixOverrides/suffixOverrides的条件满足后实行的覆盖策略-->
<!--对开头有AND或者OR的值直接替换为WHERE-->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
trim节点使用偏广泛,可以与多个节点进行搭配使用
4.set,类比数据库的set关键字(其会消除多余的,分隔符)
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
5.foreach,集合迭代输出
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
6.bind,创建额外属性变量并应用
<select id="selectBlogsLike" resultType="Blog">
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
WHERE title LIKE #{pattern}
</select>
7._paramter和_databaseId是mybatis的内部属性。
前者代表方法参数类,多与bind节点搭配使用;
后者则为mybatis主文件中databaseIdProvider节点配置的
<databaseIdProvider type="VENDOR">
<property name="Oracle" value="oracle"></property>
<property name="Mysql" value="mysql"></property>
</databaseIdProvider>
抑或是可通过Spring来指定
<bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
<property name="properties">
<props>
<prop key="Oracle">oracle</prop>
<prop key="Mysql">mysql</prop>
</props>
</property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="databaseIdProvider" ref="databaseIdProvider" />
</bean>
值得注意的是,只有上述的样例有配置过,方可使用_databaseId属性
XMLLanguageDriver
现在笔者将从源码的角度来看下mybatis是如何去解析上述的节点
mybatis默认的XML驱动为XMLLanguageDriver。从这个类去深究一发
此处直接查看其主要方法createSqlSource()
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);
return builder.parseScriptNode();
}
引出XMLScriptBuilder#parseScriptNode()方法,我们再继续观察如何创建SqlSource对象(真实目的也是为了解析SQL节点)
public SqlSource parseScriptNode() {
//获取select/update/insert/delete节点下的Sql语句节点包装成相应的SqlNode对象
//每个CRUD语句可能都有多个SqlNode对象
List<SqlNode> contents = parseDynamicTags(context);
//包装成混合型SqlNode对象,'Mixed'译为混合,很贴切的名字
MixedSqlNode rootSqlNode = new MixedSqlNode(contents);
SqlSource sqlSource = null;
//是否为动态语句
if (isDynamic) {
sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
} else {
//否则生成普通版SqlSource
sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);
}
return sqlSource;
}
笔者此处简单看下对各类节点的归类处理,也就是去看下XMLScriptBuilder#parseDynamicTags()方法
private List<SqlNode> parseDynamicTags(XNode node) {
//获取CRUD节点下所有子节点,包括文本内容<trim>等动态sql节点
List<SqlNode> contents = new ArrayList<SqlNode>();
NodeList children = node.getNode().getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
XNode child = node.newXNode(children.item(i));
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
//直接获取数据内容,类似"select * from .."纯文本语句
String data = child.getStringBody("");
TextSqlNode textSqlNode = new TextSqlNode(data);
//TextSqlNode对象主要会去检查纯文本语句是否含有'${'和'}'字符串,有则为true
if (textSqlNode.isDynamic()) {
contents.add(textSqlNode);
isDynamic = true;
} else {
//返回最普通的含有data的StaticTextSqlNode对象
contents.add(new StaticTextSqlNode(data));
}
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
String nodeName = child.getNode().getNodeName();
//获取节点名对应的NodeHandler对象,无非就是TrimNodeHandler/WhereNodeHandler等等
NodeHandler handler = nodeHandlers.get(nodeName);
if (handler == null) {
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");
}
//调用同一接口实现解析生成SqlNode对象并统一存入List<SqlNode>集合中
handler.handleNode(child, contents);
isDynamic = true;
}
}
return contents;
}
上述代码通过parseDynamicTags()方法获取的SqlNode集合是为了方便SqlSource类去真正的生成SQL语句
而org.apache.ibatis.scripting.xmltags.SqlNode是一个接口,内部只有一个apply()方法,其下有TrimSqlNode/IfSqlNode等实现类用于不同场景
小结
对上述的代码以及讲解作下简单的小结
1.mybatis默认的mapper解析驱动为org.apache.ibatis.scripting.xmltags.XMLLanguageDriver类,基本上使用此类即可
2.用户在使用
_databaseId的时候,请确保相应的databaseIdProvider已配置3.mybatis动态SQL节点的解析最终都会被包装成org.apache.ibatis.scripting.xmltags.MixedSqlSource类,里面包含了各种解析的SqlNode集合,其目的就是通过此接口来解析相应的动态SQL
4.最终保存在MappedStatement对象中的SqlSource类为org.apache.ibatis.scripting.xmltags.DynamicSqlSource,此类也比较关键,主要是用于返回String类型的SQL,后文会分析
Spring mybatis源码篇章-动态SQL基础语法以及原理的更多相关文章
- Spring mybatis源码篇章-动态SQL节点源码深入
通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-动态SQL基础语法以及原理 前话 前文描述到通过mybatis默认的解析驱动类org.apache.ibat ...
- Spring mybatis源码篇章-NodeHandler实现类具体解析保存Dynamic sql节点信息
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource SqlNode接口类 publi ...
- Spring mybatis源码篇章-sql mapper配置文件绑定mapper class类
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(二) 背景知识 MappedStatement是mybatis操作sql ...
- Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(二) 首先了解下sql mapper的动态sql语法 具体的动态sql的 ...
- Spring mybatis源码篇章-MapperScannerConfigurer关联dao接口
前言:Spring针对Mybatis的XML方式的加载MappedStatement,通过引入MapperScannerConfigurer扫描类来关联相应的dao接口以供Service层调用.承接前 ...
- Spring mybatis源码篇章-MybatisDAO文件解析(二)
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-MybatisDAO文件解析(一) 默认加载mybatis主文件方式 XMLConfigBuilder ...
- Spring mybatis源码篇章-Mybatis的XML文件加载
通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-Mybatis主文件加载 前话 前文主要讲解了Mybatis的主文件加载方式,本文则分析不使用主文件加载方式 ...
- Spring mybatis源码篇章-MybatisDAO文件解析(一)
前言:通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-SqlSessionFactory 加载指定的mybatis主文件 Mybatis模板文件,其中的属性 ...
- Spring mybatis源码篇章-Mybatis主文件加载
通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-SqlSessionFactory 前话 本文承接前文的内容继续往下扩展,通过Spring与Mybatis的 ...
随机推荐
- vue使用Echarts图表
vue使用Echarts图表 童话_xxv 关注 0.5 2018.12.11 09:09* 字数 325 阅读 1456评论 2喜欢 13 在开发后台系统时,使用图表进行数据可视化,这样会使数据更 ...
- 五十七.分布式ELK平台、ES安装 、 扩展插件 、Kibana安装
1. ES集群安装 准备1台虚拟机 部署elasticsearch第一个节点 访问9200端口查看是否安装成功 1ELK是日志分析平台,不是一款软件,而是一整套解决方案,是三个软件产品的首字母缩写 ...
- MySQL数据分析-(10)SQL基础操作之表操作
大家好,我是jacky,很高兴跟大家继续分享MySQL数据分析实战课程,前面我们学习了库层面增删改查的SQL语句,这次课jacky将给大家介绍表层面的增删改查, (一)本课时的学习逻辑 表层面的增删改 ...
- [题解] [CF1037D] Valid BFS?
题面 题解 一个是模拟BFS的过程 还有一个是可以根据给出的BFS序构树, 再看两棵树是否相同 判断相同的话, 以同一个点为根, 看两棵树中1−
- FLUENT多孔介质数值模拟设置【转载】
转载自:http://zhengjun0228.blog.163.com/blog/static/71377014200971895419613/ 多孔介质条件 多孔介质模型可以应用于很多问题,如通过 ...
- jenkins创建工程
1.新建一个工程 2.添加工程名,点击创建一个自由分格的软件项目 3.配置源码管理 4.增加工程构建步骤,选中调用顶层maven目标
- iOS-VideoToolbox硬编码H264
前言 VideoToolBox是iOS8之后,苹果开发的用于硬解码编码H264/H265(iOS11以后支持)的API. 对于H264还不了解的童鞋一定要先看下这边的H264的简介. 编码流程 我们实 ...
- vue 中引入第三方js库
以 jQuery 为例 一.绝对路径直接引入,全局可用 主入口页面 index.html 中用 script 标签引入: <script src="./static/jquery-1. ...
- 通过蓝牙共享网络设置Charles抓包
在办公室连接WiFi时,电脑和移动设备分配到的IP地址不在同一网段, 但是Android系统提供了一个非常方便的功能,可以搭建一个网络使得这两台设备处于同一网段,实现无障碍访问,使用Charles抓包 ...
- IOS项目集成ShareSDK实现第三方登录、分享、关注等功能
(1)官方下载ShareSDK iOS 2.8.8,地址:http://sharesdk.cn/ (2)根据实际情况,引入相关的库,参考官方文档. (3)在项目的AppDelegate中一般情况下有三 ...