Spring mybatis源码篇章-XMLLanguageDriver解析sql包装为SqlSource
2017-03-27 22:20
936 查看
前文主要分析了Spring中XML配置文件方式的加载MappedStatement,本文在前文的基础上简单了解下Mybatis的SQL语法并且看下CRUD节点是如何被解析的
mapper的动态sql语法
具体的动态sql的使用可在官网查看Mybatis 3 | Dynamic SQL1.if,条件判断
<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if> </select>
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>
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节点搭配使用,后者则为
settings属性指定的数据库标识id
SQL节点解析帮助类-XMLLanguageDriver
Mybatis默认XML驱动类为XMLLanguageDriver,其主要作用于解析select|update|insert|delete节点为完整的SQL语句。笔者此处直接查看主要方法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; }
SqlNode是一个接口,内部只有一个方法apply(),通过parseDynamicTags()方法获取的SqlNode集合是为了方便SqlSource类去真正的生成SQL语句
结束语
代码太多容易看的眼花缭乱,不易理解,决定缩短代码所占篇幅,宁可分门别类讲也不全一股脑灌输
下节预告
笔者认为为了更为深切的理解CRUD节点语法,我们必须准确的去查看下其中的NodeHandler接口类是如何处理不同的CRUD节点,方便我们编写SQL节点语句更精确相关文章推荐
- Spring mybatis源码篇章-NodeHandler实现类具体解析保存Dynamic sql节点信息
- Mybatis源码解析-DynamicSqlSource和RawSqlSource的区别
- Spring mybatis源码篇章-SqlSessionFactoryBean
- MyBatis-3.4.2-源码分析16:XML解析之SqlSessionFactory|SqlSession
- MyBatis-3.4.2-源码分析18:XML解析之RoleMapper userMapper = sqlSession.getMapper(RoleMapper.class)
- Spring mybatis源码篇章-MybatisDAO文件解析(二)
- spring、mybatis加载xml源码解析
- Mybatis-Spring SqlSessionTemplate 源码解析
- Spring mybatis源码篇章-MybatisDAO文件解析
- Spring mybatis源码篇章-MybatisDAO文件解析(一)
- MyBatis-3.4.2-源码分析14:XML解析之sqlElement(context.evalNodes("/mapper/sql"))
- mybatis之XML解析源码分析
- Mybatis3源码分析(11)-Sql解析执行-BoundSql的加载-1
- Mybatis 源码解析(一) - Configuration.xml加载
- spring IOC源码之解析xml中各个元素的过程
- Mybatis3源码分析(16)-Sql解析执行-结果集映射(ResultSetHandler)
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
- Mybatis3源码分析(三):解析mapper的xml配置文件
- Spring 3.2 源码解析 -- XML bean 元素到 BeanDefinition 解析过程
- Spring源码追踪2——xml解析入口