MyBatis 的动态 SQL 包括以下几种元素:

元素名称 描述 备注
if 判断语句 单条件分支判断
choose(when、otherwise) 相当于 Java 中的 case when 语句 多条件分支判断
trim(where、set) 辅助元素 用于处理一些 SQL 拼装问题
foreach 循环语句 在 IN 语句等列举条件常用

详细的使用参考官网文档:http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html

本章内容简单描述这些动态 SQL 在使用的过程中需要注意的地方。

choose, when, otherwise

比如我们要实现如下功能:

  • 当学生姓名不为空,则只用学生姓名作为条件查询
  • 当学生性别不为空,则只用学生性别作为条件查询
  • 当学生姓名和学生性别都为空,则要求学生学生证件号不为空

针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

  1. <select id="listByConditions" parameterType="studentQuery" resultMap="BaseResultMap">
  2. select
  3. <include refid="Base_Column_List" />
  4. from t_student
  5. <where>
  6. <choose>
  7. <when test="name != null and name != ''">
  8. AND name LIKE CONCAT('%', #{name}, '%')
  9. </when>
  10. <when test="sex != null">
  11. AND sex = #{sex}
  12. </when>
  13. <otherwise>
  14. AND selfcard_no is not null
  15. </otherwise>
  16. </choose>
  17. </where>
  18. </select>

trim, where, set

比如下面的动态 SQL 有什么问题?

  1. <select id="listByConditions" parameterType="studentQuery" resultMap="BaseResultMap">
  2. SELECT id, name, sex, selfcard_no, note
  3. FROM t_student
  4. WHERE
  5. <if test="ids != null and ids.size() > 0">
  6. id IN
  7. <foreach collection="ids" item="item" open="(" close=")" separator=",">
  8. #{item}
  9. </foreach>
  10. </if>
  11. <if test="name != null and name != ''">
  12. AND name LIKE CONCAT('%', #{name}, '%')
  13. </if>
  14. <if test="sex != null">
  15. AND sex = #{sex}
  16. </if>
  17. <if test="selfcardNo != null">
  18. AND selfcard_no = #{selfcardNo}
  19. </if>
  20. </select>

如果这些条件没有一个能匹配上会发生什么?最终这条 SQL 会变成这样:

  1. SELECT id, name, sex, selfcard_no, note
  2. FROM t_student
  3. WHERE

这样会导致 SQL 语句执行失败。如果仅仅第二个条件匹配又会怎样?这条 SQL 最终会是这样:

  1. SELECT id, name, sex, selfcard_no, note
  2. FROM t_student
  3. WHERE
  4. AND name LIKE CONCAT('%', 'a', '%')

这个查询也会失败。

MyBatis 提供了 元素可以解决上面的问题,将上面的动态 SQL 改成如下形式。

  1. <select id="listByConditions" parameterType="studentQuery" resultMap="BaseResultMap">
  2. SELECT id, name, sex, selfcard_no, note
  3. FROM t_student
  4. <where>
  5. <if test="ids != null and ids.size() > 0">
  6. AND id IN
  7. <foreach collection="ids" item="item" open="(" close=")" separator=",">
  8. #{item}
  9. </foreach>
  10. </if>
  11. <if test="name != null and name != ''">
  12. AND name LIKE CONCAT('%', #{name}, '%')
  13. </if>
  14. <if test="sex != null">
  15. AND sex = #{sex}
  16. </if>
  17. <if test="selfcardNo != null">
  18. AND selfcard_no = #{selfcardNo}
  19. </if>
  20. </where>
  21. </select>

foreach

实现批量新增功能,动态 SQL 如下:

  1. <insert id="batchInsertByNoAutoInc" parameterType="list">
  2. <selectKey keyProperty="id" resultType="long" order="BEFORE">
  3. select if(max(id) is null, 1, max(id) + 2) as newId from t_student
  4. </selectKey>
  5. insert into t_student (name, sex, selfcard_no, note)
  6. values
  7. <foreach collection="list" item="item" index="index" separator=",">
  8. (
  9. #{item.name,jdbcType=VARCHAR},
  10. #{item.sex,jdbcType=TINYINT},
  11. #{item.selfcardNo,jdbcType=BIGINT},
  12. #{item.note,jdbcType=VARCHAR}
  13. )
  14. </foreach>
  15. </insert>

批量新增的操作需要确保 list 中必须有值。

作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/opbeni 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。