Mybatis 动态 SQL 是做什么的
Mybatis的 动态 SQL 是指在进行 SQL 操作的时候,传入的参数对象或者参数值,根据匹配的条件,有可能需要动态的去判断是否为空,循环,拼接等情况。
动态 SQL 标签
Mybatis 提供了 9 种动态 SQL 标签:
<if/>
<choose/>、<when/>、<otherwise/>
<trim/>、<where/>、<set/>
<foreach/>
<bind/>
还有一种特殊的用于注解形式开发的 <script>
<if>
if是为了判断传入的值是否符合某种规则,比如是否不为空;<choose> <when> <otherwise>
:这是一组组合标签,他们的作用类似于 Java 中的 switch、case、default。只有一个条件生效,也就是只执行满足的条件 when,没有满足的条件就执行 otherwise,表示默认条件;
<!--动态Sql: choose、when、otherwise 标签-->
<select id="getUser" resultType="com.git.pojo.User">
select * from user
<where>
<choose>
<when test="name != null and name != ''">
AND name = #{name}
</when>
<otherwise>
AND id = #{id}
</otherwise>
</choose>
</where>
</select>
<where>
标签可以用来做动态拼接查询条件,where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。当和if标签配合的时候,不用显示的声明类似where 1=1这种无用的条件;<set>
: 功能与<where>
类似,主要用于更新操作。为了删除在if不符合判断条件下,多出来的set关键字和”,”。<trim>
标签主要用在当<where>
和<set>
标签不符合期望的时候,可以自定义返回内容。<trim>
一共有 4个参数:- prefix(前缀): 在标签内有内容时,在句首增加的字段。例:where 或者 set
- prefixOverrides(去掉的第一个标记): 例:and | or
- suffix(后缀): 在标签内有内容时,在句尾增加的字段。例:order by id
- suffixOverriides(去掉最后一个标记):例:“,”
<foreach>
标签可以把传入的集合对象进行遍历,然后把每一项的内容作为参数传到sql语句中,里面涉及到 item(具体的每一个对象), index(序号), open(开始符), close(结束符), separator(分隔符);
<!--动态Sql: foreach标签, in查询-->
<select id="dynamicSqlSelectList" resultType="com.lagou.pojo.User">
SELECT * from user WHERE id in
<foreach collection="list" item="id" open="(" close=")" separator="," >
#{id}
</foreach>
</select>
<bind>
元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
<script>
是用在带注解的映射器接口类中使用动态 SQL。需要用script标签把所有sql包裹,这样才可以正常使用上面的的各种动态标签.
动态sql的执行原理
动态 SQL 的执行整体分为两个部分:解析 和 执行
一、 SQL 解析
在项目启动 SqlSessionFactory
加载xml配置文件并进行解析,根据关键标签封装成对应的handler处理对象,封装成 sqlSource
对象存在Configuration
的 mappedStatement
中。
调用过程:
- 在
SqlSessionFactoryBuilder
的builder
方法中,封装XMLConfigBuilder
类,并调用该类的parse()
方法 进行解析。在解析过程中使用到了私有的mapperElement(XNode parent)
方法 - 在
mapperElement(XNode parent)
方法 中根据<mapper>
的资源地址获取到每一个mapper的配置文件,并构建XMLMapperBuilder
对象,之后执行解析。 - 解析过程中调用
configurationElement
方法中的buildStatementFromContext
解析<select /> <insert /> <update /> <delete />
节点 - 遍历以上四种节点,并构建
XMLStatementBuilder
对象,进行解析。 - 在解析过程中,使用
langDriver.createSqlSource()
创建SqlSource
。
这个 SqlSource 里面就存放着最后解析出来的动态SQL。
接下来是创建SqlSource
的具体解析过程。
- 在
createSqlSource()
中 首先将 节点内容 和 传入参数类型 封装为XMLScriptBuilder
。之后调用解析方法parseScriptNode()
。 - 在解析方法中执行
parseDynamicTags()
方法,会对nodeHandlers里的标签根据不同的handler来处理不同的标签。 - 最后把
DynamicContext
结果放回SqlSource中
二、 执行
在Executor
执行的时候,调用 DynamicSqlSource
的解析方法,并返回解析好的BoundSql
,和已经排好序,需要替换的参数