<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>

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

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

这个接口主要用来构造sql。下面我们来分析一下这个接口的其中几个实现类。
解析mybatis中configLocation属性中的全局xml文件。其内部会使用XMLMapperBuilder来解析各个xml文件。
遍历mybatis中mapperLocations属性中的xml文件中每个节点的Builder。比如uxer.xml,会使用XMLStatementBuilder处理xml中的每个节点。
解析xml文件中每个节点,比如select、insert、update等。内部会使用XMLScriptBuilder处理节点的Sql部分,遍历的数据会存储到Configuration的mappedStatements中。
解析xml中各个节点sql部分的builder

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

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


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

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




