暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

mybatis--------动态Sql原理分析

Lord Lean Notes 2020-03-27
1062
我们在使用mybatis时,经常会在xml中编写一些动态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的原理来进行分析。先来认识一下动态sql所涉及到的接口和类,SqlNode接口

    SqlNode接口可以理解为xml文件中的标签,比如update、if、trim等。我们可以看到有许多类都实现了SqlNode接口,比如ChooseSqlNode、ifSqlNode等。

    SqlSource接口

    Sql源接口,代表从xml文件中或注解映射的sql语句内容,主要用于创建BoundSql。实现类有DynamicSqlSource(动态sql源)、StaticSqlSource(静态sql源)等。BoundSql类里面封装了mybatis最终产生的sql类,包括sql语句、参数、参数源数据等参数。

    BaseBuilder接口

    这个接口主要用来构造sql。下面我们来分析一下这个接口的其中几个实现类。

    XMLConfigBuilder

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

    XMLMapperBuilder

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

    XMLStatementBuilder

    解析xml文件中每个节点,比如select、insert、update等。内部会使用XMLScriptBuilder处理节点的Sql部分,遍历的数据会存储到Configuration的mappedStatements中。

    XMLSriptBuilder

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

    LanguageDriver接口

    该接口的作用就是构造sql语句。我们可以看到这个接口有XMLLanguageDriver和RawLanguageDriver两个实现类。其中XMLLanguageDriver是处理xml文件中的sql,通过使用XMLScriptBuilder解析xml文件中的sql部分,而RawLanguageDriver则是处理静态sql。


    在对动态Sql语句一些接口和实现类分析完之后,现在开始从源码角度来进行分析:
      <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="configLocation" value="classpath:mybatisConfig.xml"/>
      <property name="mapperLocations" value="classpath*:org/format/dao/*.xml"/>
      </bean>

      Spring和mybaits整合的时候都需要配置SqlSessionFactoryBean,而该配置会加入数据源和mybatis.xml文件路径等信息。下面我们就来分析一下这段配置后的细节。

      首先SqlSessionFactoryBean实现了Spring的InitializingBean接口,InitializingBean接口的afterPropertiesSet方法会调用buildSqlSessionFactory方法。buildSqlSessionFactory方法内部会使用XMLConfigBuilder解析属性是configLocation中配置的路径,还会使用XMLMapperBuilder解析mapperLocations属性中的各个xml文件。部分源码如下:

      由于XMLConfigBuilder也是使用XMLMapperBuilder,所以下面来看下XMLMapperBuilder的解析细节:


      下面我们来关注一下增删改查节点的解析:

      我们可以看到每个节点都是使用的XMLStatementBuilder来解析的。

      而在XMLStatementBuilder中会使用LanguageDriver来解析sql,并得到SqlSource对象。其默认会使用XMLanguageBuilder来创建SqlSource,并且使用XMLScriptBuilder来处理节点的sql部分。

      在解析节点的过程中遇到子节点的情况下会采用遍历的方式来解析。

      当得到SqlSource对象之后,就可以拿到BoundSql对象,以此来拿到最终的sql语句。

      在这里可以引出一个问题,问什么下图中xml文件总sql语句的内容是不相同的,但是在解析后的内容确是相同的呢?

      下面就拿TrimSqlNode节点来解析,看看其是怎么处理prefix和suffix内容的:

      通过上面几张图可以看出在parseDynamicTags方法中解析子节点后会返回存储着所有sqlNode节点的集合,并把这个集合封装到了MixedSqlNode对象中。在获取BoundSql对象时,会遍历存储着所有sqlNode节点的集合,并调用apply方法,通过FilteredDynamicContext来过滤掉prefix和suffix。

      文章转载自Lord Lean Notes,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论