概述

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
动态SQL的思想:就是使用不同的动态SQL标签去完成字符串的拼接处理、循环判断。

解决问题

1、在映射文件中,会编写很多有重叠部分的SQL语句,比如SELECT语句和WHERE语句等这些冗余的sql语句,该如何 处理
2、SQL语句中的where条件有多个,但是页面只传递过来一个条件参数,此时会发生问题。

代码示例

根据用户名称模糊查询用户信息

if标签

综合查询的案例中,查询条件是由页面传入,页面中的查询条件可能输入用户名称,也可能不输入用户名称。
if标签包含的属性如下

  1. test:判断条件
  1. <select id="findUserList" resultType="com.example.kkbstudy.pojo.User">
  2. select * from `user` where 1=1
  3. <if test="name !=name != null and name != ''">
  4. name = #{name}
  5. </if>
  6. </select>

注意:要做『不等于空』字符串校验。

where标签

上边的sql中的1=1,虽然可以保证sql语句的完整性:但是存在性能问题。Mybatis提供where标签解决该问题。
where标签包含的属性如下
代码修改如下:

  1. <select id="findUserList" resultType="com.example.kkbstudy.pojo.User">
  2. select * from `user`
  3. <!-- where标签会处理它后面的第一个and -->
  4. <where>
  5. <if test="name !=name != null and name != ''">
  6. and name = #{name}
  7. </if>
  8. </where>
  9. </select>

sql片段

在映射文件中可使用sql标签将重复的sql提取出来,然后使用include标签引用即可,最终达到sql重用的目的
sql标签包含的属性如下:

  1. id: 这段sql的唯一标识
  2. lang:
  3. databaseId:

include标签属性如下

  1. refid:指向引用sqlid
  1. <!-- 将查询字段抽取出来:-->
  2. <sql id="selectColumn">
  3. id,`name`
  4. </sql>
  5. <!-- 将where条件抽取出来:-->
  6. <sql id="queryUserWhere">
  7. <if test="name !=name != null and name != ''">
  8. and name = #{name}
  9. </if>
  10. </sql>
  11. <select id="findUserList" resultType="com.example.kkbstudy.pojo.User">
  12. select <include refid="selectColumn"/> from `user`
  13. <!-- where标签会处理它后面的第一个and -->
  14. <where>
  15. <!-- 使用include引用 -->
  16. <include refid="queryUserWhere"/>
  17. </where>
  18. </select>

注意: 1、如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,
如下:

  1. <include refid="namespace.sql片段”/>

foreach

需求
综合查询时,传入多个id查询用户信息,用下边两个sql实现:

  1. SELECT * FROM USER WHERE username LIKE '%老郭%' AND (id =1 OR id =10 OR id=16)
  2. SELECT * FROM USER WHERE username LIKE '%老郭%' AND id IN (1,10,16)

当需要在xml里实现这样效果的时候就需要用到foreach标签。
foreach标签包含的属性如下:

  1. collection:指定输入的集合参数的参数名称
  2. item:声明集合参数中的元素变量名
  3. index:集合遍历时的下标
  4. open:集合遍历时,需要拼接到遍历sql语句的前面
  5. close:集合遍历时,需要拼接到遍历sql语句的后面
  6. separator:集合遍历时,需要拼接到遍历sql语句之间的分隔符号

用户pojo添加ids字段

  1. private List<Integer> ids;

这样最终的mapper就变成了了这样

  1. <!-- 将查询字段抽取出来:-->
  2. <sql id="selectColumn">
  3. id,`name`
  4. </sql>
  5. <!-- 将where条件抽取出来:-->
  6. <sql id="queryUserWhere">
  7. <if test="name !=name != null and name != ''">
  8. and name = #{name}
  9. </if>
  10. <if test="ids != null and ids.size() > 0">
  11. <foreach collection="ids" item="id" open=" AND id IN ( " close=" ) " separator=",">
  12. #{id}
  13. </foreach>
  14. </if>
  15. </sql>
  16. <select id="findUserList" resultType="com.example.kkbstudy.pojo.User">
  17. select <include refid="selectColumn"/> from `user`
  18. <!-- where标签会处理它后面的第一个and -->
  19. <where>
  20. <!-- 使用include引用 -->
  21. <include refid="queryUserWhere"/>
  22. </where>
  23. </select>

注意:
如果parameterType不是POJO类型,而是List或者Array的话,那么foreach语句中,collection属性值需要固定 写死为list或者array。
如下

  1. <select id="findUserListByIds" resultType="com.example.kkbstudy.pojo.User">
  2. select <include refid="selectColumn"/> from `user`
  3. <where>
  4. <if test="list != null and list.size()>0">
  5. <foreach collection="list" item="id" open=" AND id IN ( " close=" ) " separator=",">
  6. #{id}
  7. </foreach>
  8. </if>
  9. </where>
  10. </select>

trim

mybatis的trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于选择性插入、更新、删除或者条件查询等操作。
trim标签的包含的属性如下

  1. prefix:给sql语句拼接的前缀
  2. prefixOverrides:去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
  3. suffix:给sql语句拼接的后缀
  4. suffixOverrides:去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定
  1. <trim prefix="where" prefixOverrides="AND |OR " suffix=";" suffixOverrides=",">
  2. </trim>

set

在动态 update 语句中可以使用 元素动态更新列。

  1. <update id="update" parameterType="com.example.kkbstudy.pojo.User">
  2. update `user`
  3. <set>
  4. <if test="name !=null and name != ''">
  5. name = #{name}
  6. </if>
  7. </set>
  8. where id #{id}
  9. </update>

choose

有些时候不想用到所有的条件语句,而只想从中择取一二,针对这种情况,MyBatis 提供了 元素,和一起使用,它有点像 Java 中的 switch 语句。**

  1. <!--使用choose、when、otherwise元素根据条件动态查询用户信息-->
  2. <select id="selectUserByChoose" resultType="com.example.kkbstudy.pojo.User" parameterType= "com.example.kkbstudy.pojo.User">
  3. select * from `user` where 1=1
  4. <choose>
  5. <when test="name!=null and name!=''">
  6. and `name` like concat('%',#{name},'%')
  7. </when>
  8. <otherwise>
  9. and id > 10
  10. </otherwise>
  11. </choose>
  12. </select>

bind

在进行模糊查询时,如果使用“${}”拼接字符串,则无法防止 SQL 注入问题。如果使用字符串拼接函数或连接符号,但不同数据库的拼接函数或连接符号不同。

例如 MySQL 的 concat 函数、Oracle 的连接符号“||”,这样 SQL 映射文件就需要根据不同的数据库提供不同的实现,显然比较麻烦,且不利于代码的移植。幸运的是,MyBatis 提供了 元素来解决这一问题。

  1. <!--使用bind元素进行模糊查询-->
  2. <select id="selectUserByBind" resultType="com.example.kkbstudy.pojo.User" parameterType= "com.example.kkbstudy.pojo.User">
  3. <!-- bind 中的 name 是 com.example.kkbstudy.pojo.User 的属性名-->
  4. <bind name="paran_name" value="'%' + name + '%'"/>
  5. select * from `user` where `name` like #{paran_name}
  6. </select>