MyBatis SqlSource源码示例解析

正文

MyBatis版本:3.5.12。

本篇讲从mybatis的角度分析SqlSource。在xml中sql可能是带?的预处理语句,也可能是带$或者动态标签的动态语句,也可能是这两者的混合语句。

SqlSource设计的目标就是封装xml的crud节点,使得mybatis运行过程中可以直接通过SqlSource获取xml节点中解析后的SQL。

简单的示意图就是

MyBatis SqlSource源码示例解析_第1张图片

接下来我们先来介绍几个基础的组件,正是这些组件构成的SqlSource

SqlNode

mybatis提供了这么9种动态节点:

  • trim
  • where
  • set
  • foreach
  • if
  • choose
  • when
  • otherwise
  • bind

每一种节点是一个SqlNode,并且每个动态节点都分别对应了一个XxxSqlNode的实现类。SqlNode是一个接口,该接口就代表mybatis的动态节点。

MyBatis SqlSource源码示例解析_第2张图片

接下来我们来用一个案例分析mybatis是如何把一个 select * from user and id = #{id} and age > ${age}

它会被解析成如下这样一颗SqlNode树

MyBatis SqlSource源码示例解析_第3张图片

树的根节点都是MixedSqlNodeMixedSqlNode类其中有一个属性private final List contents;专门存放标签下所有的子节点解析成的SqlNode

该标签的的第一部分就是select * from user;这段文本既不包含标签,也不包含$等表达式,它就属于静态文本,会被解析成StaticTextSqlNode

  • 然后与接下来是一个wehre标签,它会被解析为WhereSqlNode
  • whhre标签中有两个if标签,这两个if标签会被解析为两个IfSqlNode加入到WhereSqlNode
  • 第一个if标签中的文本不包含$会被解析成StaticTextSqlNode(没错,即使它有#符,它不属于静态文本哦。只有包含$才算动态节点)
  • 而第二个if标签中的文本包含$会被解析成TextSqlNode

看明白了xml文件中一个标签是如何由这些SqlNode是组成的。接下来我们唠一唠SqlNode接口的定义

SqlNode接口定义

public interface SqlNode {
  boolean apply(DynamicContext context);
}

SqlNode接口定义非常简单,只有一个apply方法,方法的参数是DynamicContextDynamicContext可以看作是一个sql上下文,它其中维护了一个StringBuilder sql字段。这个字段就是用来记录整个