文章目录

  • 动态sql
  • if
  • choose(when、otherwise)
  • trim(where、set)
  • foreach
  • sql片段



动态sql

动态SQL是MyBatis的强大特性之一,利用动态SQL,我们能根据不同条件灵活的拼接SQL语句。常用的动态SQL标签有如下几种:

  • if
  • choose(when、otherwise)
  • trim(where、set)
  • foreach

if

使用<if>sql</if>时,如果满足条件,则会将sql和前面的sql片段拼接起来,示例如下:

<select id="selectStudentIf" resultType="com.example.entity.Student">
    select * from student
    where 1 = 1
    <if test="name != null and name != ''">
        and name = #{name}
    </if>
    <if test="age > 0">
        and age > #{age}
    </if>
</select>

如果name的值为null,或者值为空字符串,则and name = #{name}sql片段将不会与前文sql拼接,如果上述例子的两个条件均满足,则最终形成的sql语句为:

select * from student where 1 = 1 and name = #{name} and age > #{age}

注意事项:在上述例子中,我们第一次看时不免会感到疑惑,1 = 1这个条件不是多余的吗?其实,仔细思考后,我们会发现,如果去掉该条件,当第一个条件不满足时(即name值为null或者为空字符串),形成的sql语句为:

select * from student where and age > #{age}

显然,该sql语句是存在错误的,and应该去除,如果加上在and前加上一个恒成立的条件,就可以解决这个问题,此外,我们还可以借助<where>来解决这个问题(见下文)。

choose(when、otherwise)

<choose>有点类似switch-case,使用该标签,会从多个条件中选择一个使用,示例如下:

<select id="selectStudentIf" resultType="com.example.entity.Student">
	select * from student
    where 1 = 1
    <choose>
    	<!-- 条件1 -->
		<when test="name != null and name != ''">
            and name = #{name}
        </when>
        <!-- 条件2 -->
        <when test="age > 0">
            and age > #{age}
        </when>
        <otherwise>
            and id < #{id}
        </otherwise>
    </choose>
</select>

如上所示,可分为三种情况:

  1. 条件1、2均满足,结果选择条件1中的sql语句,最终结果为:
select * from student where 1 = 1 and name = #{name}
  1. 条件1、2中只有其中一个满足时,选择满足条件中的sql语句,最终结果为:
<!-- 条件1满足 -->
select * from student where 1 = 1 and name = #{name}

<!-- 条件2满足 -->
select * from student where 1 = 1 and age > #{age}
  1. 条件1、2均不满足时,选择<otherwise>中的sql语句(如果使用了该标签),最终结果为:
select * from student where 1 = 1 and id < #{id}

trim(where、set)

  • where
    使用<where>,能够解决我们在上文if标签示例中提到的问题,示例如下:
<select id="selectStudentWhere" resultType="com.example.entity.Student">
	select * from student
	<where>
		<!-- 条件1 -->
		<if test="name != null and name != ''">
			name = #{name}
		</if>
		<!-- 条件2 -->
		<if test="age > 0">
			or age > #{age}
		</if>
	</where>
</select>

当条件1不满足,条件2满足时,最终结果为:

select * from student where age > #{age}

此时不会再出现多余的and | or,where标签自动为我们去除了多余的and或者or,得到正确的sql语句。

  • set
<update id="updateSet">
	update student
	<set>
		<if test="name != null">name = #{name},</if>
		<if test="age > 0">age = #{age},</if>
		<!-- 条件3 -->
		<if test="email != null">email = #{email}</if>
	</set>
	where id = #{id}
</update>

如上述例子,如果条件3不满足,前两个条件至少有1个满足时,则最终的sql语句会出现多余的,使用<set>则能够去除多余的逗号,得到正确的sql语句。

  • trim
    如果上述的whereset标签结果与我们的期望不同,可以通过自定义trim标签来定制where和set标签的功能,例如,和where、set标签等价的自定义trim标签分别如下:
<trim prefix="WHERE" prefixOverrides="AND | OR">
	...
</trim>

<trim prefix="SET" suffixOverrides=",">
	...
</trim>

foreach

foreach标签在对集合进行遍历的场景下使用(例如:in条件语句),示例如下:

<select id="selectForeachOne" resultType="com.example.entity.Student">
	select * from student where id in
	<foreach collection="list" item="myid" open="(" close=")" separator=",">
		#{myid}
	</foreach>
</select>

如果遍历的集合中的元素是自定义的类,例如:List<Student>,item=“stu”,使用id属性的值时,则#{myid}改为#{stu.id}即可。
foreach标签中各属性值说明:

collection:表示接口中的方法参数的类型,如果是数组,使用array,如果是list则使用list
item:自定义,表示数组和集合成员的变量
open:循环开始时的字符
close:循环结束时的字符
separator:集合成员之间的分隔符

sql片段

步骤:

  1. 先定义<sql id=“自定义名称(唯一)”> sql语句,表名,字段等</sql>
  2. 再使用<include refid=“id的值”/>
    示例如下:
<sql id="studentSql">
	select * from student
</sql>

<!-- 使用 -->
<select id="selectStudentIf" resultType="com.example.entity.Student">
    <include refid="studentSql"/>
    ...
</select>