Mybatis解析动态SQL原理

824 阅读2分钟

我们在使用mybatis的时候,会在xml中编写sql语句。

比如这段动态sql代码:

<update id="update" parameterType="org.format.dynamicproxy.mybatis.bean.User">
    UPDATE users
    <trim prefix="SET" prefixOverrides=",">
        <if test="name != null and name != ''">
            name = #{name}
        </if>
        <if test="age != null and age != ''">
            , age = #{age}
        </if>
        <if test="birthday != null and birthday != ''">
            , birthday = #{birthday}
        </if>
    </trim>
    where id = ${id}

</update>

mybatis底层是如何构造这段sql的?带着这个疑问,我们一步一步分析

介绍MyBatis中一些关于动态SQL的接口和类

SqlNode接口,简单理解就是xml中的每个标签,比如上述sql的update,trim,if标签:

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

image.png SqlSource Sql源接口,代表从xml文件或注解映射的sql内容,主要就是用于创建BoundSql,有实现类DynamicSqlSource(动态Sql源),StaticSqlSource(静态Sql源)等:

**public** **interface** **SqlSource** {
  BoundSql **getBoundSql**(Object parameterObject);
}

image.png BoundSql类,封装mybatis最终产生sql的类,包括sql语句,参数,参数源数据等参数:

image.png XNode,一个Dom API中的Node接口的扩展类。

image.png BaseBuilder接口及其实现类(属性,方法省略了,大家有兴趣的自己看),这些Builder的作用就是用于构造sql:

image.png

下面我们简单分析下其中4个Builder:

  1. XMLConfigBuilder

    解析mybatis中configLocation属性中的全局xml文件,内部会使用XMLMapperBuilder解析各个xml文件。

  2. XMLMapperBuilder

    遍历mybatis中mapperLocations属性中的xml文件中每个节点的Builder,比如user.xml,内部会使用XMLStatementBuilder处理xml中的每个节点。

  3. XMLStatementBuilder

    解析xml文件中各个节点,比如select,insert,update,delete节点,内部会使用XMLScriptBuilder处理节点的sql部分,遍历产生的数据会丢到Configuration的mappedStatements中。

  4. XMLScriptBuilder

    解析xml中各个节点sql部分的Builder。

LanguageDriver接口及其实现类(属性,方法省略了,大家有兴趣的自己看),该接口主要的作用就是构造sql:

image.png 简单分析下XMLLanguageDriver(处理xml中的sql,RawLanguageDriver处理静态sql):

XMLLanguageDriver内部会使用XMLScriptBuilder解析xml中的sql部分。

以上是比较重要的类我们都已经介绍了,下面则是源码分析。

源码分析

SqlSessionFactory方法内部会使用XMLConfigBuilder解析属性configLocation中配置的路径,还会使用XMLMapperBuilder属性解析mapperLocations属性中的各个xml文件。部分源码如下:

image.png 由于XMLConfigBuilder内部也是使用XMLMapperBuilder,我们就看看XMLMapperBuilder的解析细节。

image.png

image.png 我们关注一下,增删改查节点的解析。

image.png XMLStatementBuilder的解析:

image.png 默认会使用XMLLanguageDriver创建SqlSource(Configuration构造函数中设置)。

XMLLanguageDriver创建SqlSource:

image.png XMLScriptBuilder解析sql:

image.png 得到SqlSource之后,会放到Configuration中,有了SqlSource,就能拿BoundSql了,BoundSql可以得到最终的sql。