MyBatis动态SQL

本文详细介绍了MyBatis的动态SQL功能,包括if、where、trim、choose、when、otherwise、foreach以及SQL片段的用法。通过实例展示了如何在不同场景下使用这些标签来拼接SQL,实现条件过滤、批量操作等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态sql,就是MyBatis中有一些标签,可以帮助我们来拼接sql。

一、 if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行。
应用场景:表单展示中通过过滤条件展示数据。
比如可以根据年龄或者性别查询员工数据。
输入参数两种取值可能,空字符串和null。
**Example:**根据年龄,部门,或者性别过滤查询。
mapper中查询函数定义:

List<Employee> getEmpByFilter(@Param("filter")Filter filter);

过滤条件Filter定义为:

package com.lucky.mybatis.bean;

public class Filter {
    private String gender;

    private int age;

    private int departmentId;

    public Filter() {
    }

    public Filter(String gender, int age, int departmentId) {
        this.gender = gender;
        this.age = age;
        this.departmentId = departmentId;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getDepartmentId() {
        return departmentId;
    }

    public void setDepartmentId(int departmentId) {
        this.departmentId = departmentId;
    }

    @Override
    public String toString() {
        return "Filter{" +
                "gender='" + gender + '\'' +
                ", age=" + age +
                ", departmentId=" + departmentId +
                '}';
    }
}

xml文件sql定义为

 <select id="getEmpByFilter" resultMap="emp">
        select * from t_emp where
        <if test="filter.gender != null and filter.gender != '' ">
            gender = #{filter.gender}
        </if>

        <if test="filter.age != null and filter.age != '' ">
            and age = #{filter.age}
        </if>

        <if test="filter.departmentId != null and filter.departmentId != '' ">
            and demp_id = #{filter.departmentId}
        </if>
    </select>

测试类

 @Test
    public void testIf() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        Filter filter = new Filter("n", 22, 1);
        List<Employee> employees = empMapper.getEmpByFilter(filter);
        employees.forEach(System.out::println);
    }

上面这个测试类中,filter三个属性是全部传入的,那如果只传入两个呢?

 @Test
    public void testIf2() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession();
        EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
        // 只用年龄和部门过滤
        Filter filter = new Filter( 22, 1);
        List<Employee> employees = empMapper.getEmpByFilter(filter);
        employees.forEach(System.out::println);
    }

这里就会出错,看一下Mybatis生成的sql语句为:
在这里插入图片描述where 后面多了一个and关键字。这时候就需要where标签来动态生成where条件了。

二、where

只使用if标签,第一个条件不传入,where后面直接跟了and,会报错。或者条件都不传入,这样生成sql中多了where标签。

方法1: 使用where标签,动态生成where关键字,并且去除生成sql中多余的and关键字,如果条件都不成立,不生成where标签。
where标签通常和if标签结合使用。

 <select id="getEmpByFilter" resultMap="emp">
        select * from t_emp
        <where>
            <if test="filter.gender != null and filter.gender != '' ">
                gender = #{filter.gender}
            </if>

            <if test="filter.age != null and filter.age != '' ">
                and age = #{filter.age}
            </if>

            <if test="filter.departmentId != null and filter.departmentId != '' ">
                and demp_id = #{filter.departmentId}
            </if>
        </where>

生成sql语句为:
在这里插入图片描述

方法1: where 1=1

<select id="getEmpByFilter" resultMap="emp">
        select * from t_emp where 1=1
        <if test="filter.gender != null and filter.gender != '' ">
            gender = #{filter.gender}
        </if>

        <if test="filter.age != null and filter.age != '' ">
            and age = #{filter.age}
        </if>

        <if test="filter.departmentId != null and filter.departmentId != '' ">
            and demp_id = #{filter.departmentId}
        </if>
    </select>

生成sql语句为:
在这里插入图片描述

三、trim

如下所示,and 关键字放到if标签内容的后面。测试时过滤条件不传入最后一个书香。

 <select id="getEmpByFilter" resultMap="emp">
        select * from t_emp
        <where>
            <if test="filter.gender != null and filter.gender != '' ">
                gender = #{filter.gender} and
            </if>

            <if test="filter.age != null and filter.age != '' ">
                age = #{filter.age} and
            </if>

            <if test="filter.departmentId != null and filter.departmentId != '' ">
                demp_id = #{filter.departmentId}
            </if>
        </where>

    </select>

这样的话,生成sql如下所示。如果最后一个条件为空这样生成sql里面就多了一个and。
![在这里插入图片描述](https://img-blog.csdnimg.cn/1be62d2eaaec4222abd473cd547f8412.png
where无法去除后面and。。这时候就需要trim标签了。
常用属性:
prefix:在trim标签中的内容的前面添加某些内容
prefixOverrides:在trim标签中的内容的前面去掉某些内容
suffix:在trim标签中的内容的后面添加某些内容
suffixOverrides:在trim标签中的内容的后面去掉某些内容
我们需要在标签前加where,并且删除trim标签中后面多余的and。也就是:

 <select id="getEmpByFilter" resultMap="emp">
        select * from t_emp
        <trim prefix="where" suffixOverrides="and">
            <if test="filter.gender != null and filter.gender != '' ">
                gender = #{filter.gender} and
            </if>

            <if test="filter.age != null and filter.age != '' ">
                age = #{filter.age} and
            </if>

            <if test="filter.departmentId != null and filter.departmentId != '' ">
                demp_id = #{filter.departmentId}
            </if>
        </trim>

四、choose、when、otherwise

choose、when、 otherwise相当于if…else if…else
和if标签的区别:if每个条件都判断,choose、when、 otherwise只要有一个条件成立就不判断了。
when 至少一个, otherwise最多一个。

五、foreach

用来进行批量操作的标签
collections属性,如果参数没有使用@param指定参数名称,mybatis会自定将这个参数放到map中,并且key设置为list(假设传入参数类型为List),array的话key就是array。所以访问的时候,要用list(array).

<foreach collection="list" item="emp" separator=",">

item 循环变量
index 下标
separator forEach循环中分割符
open、close 设置当前循环由什么开始,由什么结束
批量添加

/**
     * 批量插入员工信息
     *
     * @param employees employees
     * @return int
     */
    int insertEmps(@Param("emps") List<Employee> employees);
 <insert id="insertEmps"  useGeneratedKeys="true" keyProperty="id">
      insert into t_emp values
      <foreach collection="emps" item="emp" separator=",">
        (null, #{emp.name},#{emp.age},#{emp.gender}, #{emp.departmentId})
      </foreach>
    </insert>

批量删除
方法1: delete in
delete 的时候 in里面的所有id要被()包围起来,这样就需要close和open属性了。

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

方法2: where id = or id =

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

六、SQL片段

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

<sql id="empColumns">
		eid,ename,age,sex,did
</sql>
select <include refid="empColumns"></include> from t_emp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值