动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
背景: 我们在编写一些sql查询的过程时,根据条件进行sql的拼接是很麻烦而且容易出错。而mybatis动态sql标签,正好可以解决这个烦人的问题。
mybatis常用的动态sql标签主要有以下几种:
标签 | 作用 |
---|---|
if | 单条件分支,相当于判断语句 |
choose、when、otherwise | 多条件分支,相当于Java中的switch语句 |
set、where、trim | 辅助条件判断,用于拼接语句 |
foreach | 集合进行遍历(尤其是在构建 IN 条件语句的时候) |
bind | 创建一个变量,并将其绑定到当前的上下文 |
if 标签最常见情景是根据条件包含 where 子句的一部分,通过判断参数值来决定是否使用某个条件。
<select id="findUser" resultType="User">
SELECT * FROM user
WHERE class = '160801'
<if test="age != null">
AND age > #{age}
</if>
</select>
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。choose执行过程中按顺序判断 when 中的条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when的条件都不满则时,则执行 otherwise 中的 sql。
<select id="getUser" resultMap="User">
SELECT * from STUDENT WHERE 1=1
<where>
<choose>
<when test="name!= null">
AND name like #{name}
</when>
<when test="phone != null and address != null">
AND age > #{age}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</where>
</select>
在 update 语句中使用 if 标签时,如果最后的 if 没有执行,会导致逗号多余错误。使用 set 标签可以动态地在行首插入set关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
#如果最后的if没有执行,会导致逗号多余错误。
<update id="updateUser">
update User SET
<if test="name != null">
name =#{name},
</if>
<if test="age != null">
age=#{age},
</if>
<if test="phone != null">
phone =#{phone},
</if>
<if test="class != null">
class=#{class}
</if>
where id=#{id}
</update>
#set标签除掉条件末尾的逗号
<update id="updateUser">
update User
<if test="name != null">
name=#{name},
</if>
<if test="age != null">
age=#{age},
</if>
<if test="phone != null">
phone=#{phone},
</if>
<if test="class != null">
adress=#{adress}
</if>
where class=#{class}
</update>
where 标签只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。这样我们就不用在where后面加一个1=1了
<select id="findUser" resultType="User">
SELECT * FROM user
<where>
<if test="class != null">
AND class = #{class}
</if>
<if test="phone != null and adress != null">
AND age > #{age}
</if>
</where>
</select>
set 和 where 其实都是 trim 标签的一种类型, 该两种功能都可以使用 trim 标签进行实现。如果你不满足于where和set实现的功能你就可以使用trim来自定义实现。其中trim有四个主要的属性,分别是:
自定义实现3.1的set,去除update语句后缀多余的逗号
<update id="updateUser" resultType="User">
update user set
<trim suffixOverrides=",">
<if test="class != null">
class = #{class},
</if>
<if test="phone != null and adress != null">
age > #{age},
</if>
</trim>
where class=#{class}
</update>
自定义实现3.2的where,去除where子句前缀多余的AND
<select id="findUser" resultType="User">
select * from user
<trim prefix="WHERE" prefixOverrides="AND | OR">
<if test="class != null">
AND class = #{class}
</if>
<if test="phone != null and adress != null">
AND age > #{age}
</if>
</trim>
</select>
在进行批量操作的时候,使用比较多的一个场景就是对集合进行遍历,尤其是在构建 IN 条件语句的时候。
<select id="findUser" resultType="User">
SELECT * FROM user
where class in
<foreach item="item" index="index" collection="classList" open="(" separator="," close=")">
#{item}
</foreach>
</select>
foreach中的属性:
bind标签表示在表达式以外创建一个变量,并将其绑定到当前的上下文。
<select id="queryUser" resultType="User">
<bind name="pattern" value="'%' + name + '%'" />
SELECT * FROM user
WHERE name LIKE #{name}
</select>
参考文章:mybatis官网文档