MyBatis框架 — 动态SQL

327 阅读4分钟

开发人员在使用JDBC或者其他类似的框架进行数据库开发时,通常都要根据需求去手动拼装SQL,这是一个非常麻烦且痛苦的工作,而MyBatis提供的对SQL语句动态组装的功能,恰能很好的解决这一麻烦工作。

动态SQL是MyBatis的强大特性之一,其主要元素如下:

元素说明
< if >判断语句,用于条件单分支判断
< choose >相当于Java中的switch语句,用于多分支判断
< where >,< trim >,< set >辅助元素,用于处理一些SQL的拼装,特殊字符等问题
< foreach >循环语句,常用于in语句等列举条件
< bind >用于模糊查询

1. < if > 元素

在MyBatis中,< if > 是最常用的判断语句,它类似于Java中的if语句,主要用于实现某些简单的条件选择

<select id="getEmpByyCondition" resultType="com.atguigu.mybatis.pojo.Emp">
    select * from t_emp where 1=1
        <if test="empName!=null and empName!=''">
            and emp_name=#{empName}
        </if>
        <if test="age!=null and age!=''">
            and age=#{age}
        </if>
        <if test="gender!=null and gender!=''">
            and gender=#{gender}
        </if>
</select>

2. < where >

如上述使用if语句查询我们注意到select * from t_emp where 1=1在语句中要添加where 1=1这是为了保证至少有条件成立,不至于程序报错,但是MyBatis的开发者设计了更好的方法,就是把< where >也作为元素,动态添加where,使用如下

 <select id="getEmpByConditionTwo" resultType="Emp">
     select * from t_emp
     <where>
         <if test="empName != null and empName != ''">
             emp_name = #{empName}
         </if>
         <if test="age != null and age != ''">
             and age = #{age}
         </if>
         <if test="gender != null and gender != ''">
             and gender = #{gender}
         </if>
    </where>
</select>

3. < choose >,< when >,< otherwise >元素

在使用< if >元素时,只要test属性中的表达式为true,就会执行元素中的条件语句,但是在实际应用中,有时只需要从多个选项中选择一个去执行。在这种场景下,使用< if > 元素进行处理是非常不合理的。如果使用的是Java语言,这种情况显然更适合switch语句来处理,那么MyBatis中有没有类似的语句呢?当然是有的。针对上面的情况,MyBatsi可以用< choose >,< when >,< otherwise >元素组合去实现上面的情况。

    <select id="getEmpByChoose" resultType="Emp">
        select * from t_emp
        <where>
            <choose>
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="gender != null and gender != ''">
                    gender = #{gender}
                </when>
            </choose>
        </where>
    </select>

4. < trim >元素

trim元素用于自定义拼接SQL语句,与where类似,具体我们可以对比来看

< where >

     <select id="getEmpByConditionTwo" resultType="Emp">
        select * from t_emp
        <where>
            <if test="empName != null and empName != ''">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </where>
    </select>

< trim >版

    <select id="getEmpByCondition" resultType="Emp">
        select <include refid="empColumns"></include> from t_emp
        <trim prefix="where" suffixOverrides="and">
            <if test="empName != null and empName != ''">
                emp_name = #{empName} and
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                gender = #{gender}
            </if>
        </trim>
    </select>

trim用于去掉或添加标签中的内容

常用属性:

  • prefix:在trim标签中的内容的前面添加某些内容
  • prefixOverrides:在trim标签中的内容的前面去掉某些内容
  • suffix:在trim标签中的内容的后面添加某些内容
  • suffixOverrides:在trim标签中的内容的后面去掉某些内容

5. < set >元素

在更新表中字段时,根据条件进行判断,从而实现部分更改,而不是更新所有字段,提高开发效率

    <update id="updateColumns" parameterType="Emp">
        update t_emp 
        <set>
            <if test="empName != null and empName != ''">
                emp_name = #{empName} and
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                gender = #{gender}
            </if>
        </set>
    </update>

其中的< if >元素用于判断相应的字段是否传入值,如果传入的字段非空,就将此字段进行动态SQL组转;并更新此字段,否则此字段不更新。

注意:在映射文件中使用 < set >< if >元素组合纪念性update语句动态SQL组转时,如果< set >元素内包含的内容都为空,则会出现SQL语法错误。所以在使用< set > 元素进行字段信息更新时,要确保传入的更新字段都不能为空。

6. < foreach >元素

用于SQL语句执行批量操作

  • collection: 需做foreach(遍历)的对象,作为入参时,list、array对象时,collection属性值分别默认用"list"、"array"代替,Map对象没有默认的属性值。但是,在作为入参时可以使用@Param(“keyName”)注解来设置自定义collection属性值,设置keyName后,list、array会失效;
  • item: 集合元素迭代时的别名称,该参数为必选项;
  • index: 在list、array中,index为元素的序号索引。但是在Map中,index为遍历元素的key值,该参数为可选项;
  • open: 遍历集合时的开始符号,通常与close=")"搭配使用。使用场景IN(),values()时,该参数为可选项;
  • separator: 元素之间的分隔符,类比在IN()的时候,separator=“,”,最终所有遍历的元素将会以设定的(,)逗号符号隔开,该参数为可选项;
  • close: 遍历集合时的结束符号,通常与open="("搭配使用,该参数为可选项;

6.1 添加批量数据

     <insert id="insertEmps">
        insert into t_emp value
        <foreach collection="emps" item="emp" separator=",">
          (null,#{emp.empName},#{emp.age},#{emp.gender},null)
        </foreach>
    </insert>

6.2 批量删除数据

    <delete id="deleteByEmpIds">
        delete from t_emp where emp_id in
        <foreach collection="empIds" item="empId" separator="," open="(" close=")">
            #{empId}
        </foreach>
    </delete>

也可以这么拼接SQL语句

<delete id="deleteByEmpIds">
    delete from t_emp where
    <foreach collection="empIds" item="empId" separator="or" >
        emp_id=#{empId}
    </foreach>
</delete>

7. < SQL >元素

sql片段,可以记录一段公共sql片段,在使用的地方通过include标签进行引用

<sql id="empColumns"> emp_id,emp_name,age,gender</sql>

<select id="selectAll" resultType="com.atguigu.mybatis.pojo.Emp">
    select <include refid="empColumns"></include> from t_emp
</select>