借助 Mybatis 的动态 SQL 解决传参不确定问题


在上一篇的:Mybatis 操作数据库的基本 CRUD 以及查询操作详析_@糊糊涂涂的博客-CSDN博客中介绍了Mybatis使用固定SQL语句操作数据,本篇介绍 Mybatis 一个强大的特性:动态SQL。

动态 SQL 解决什么问题?

        那当我们要执行的业务逻辑有很多,比如给成绩表中插入一行数据,对应学生的 “性别” 字段是非必须参数时,使用动态SQL就不用写两种插入语句(传与不传性别);

        另外,当执行查询逻辑时,条件中的参数个数也是不确定的。

        以上类似传入参数不确定的情况,都可以使用动态SQL来解决。


1. <if> 标签:

         <if>标签可以用来判断参数是否符合预期值,从而决定 SQL 语句的拼接;

        下面假设要给 student 表插入一行数据,学生的 sex 字段对应的实体类中 sex 属性值为null,借助<if>标签判断是否要在插入时插入 sex :

Maper 接口: 

@Mapper
public interface StudentMapper {
    // 新增学生信息
    int addStu(Student student);
}

 插入语句:

<mapper namespace="com.example.demo.mapper.StudentMapper">
    <insert id="addStu">
        insert into student (uid, name
        <if test="sex != null and sex != '' ">
            ,sex
        </if>
        ,score
        ) values (#{uid}, #{name}
        <if test="sex != null and sex != '' ">
            ,#{sex}
        </if>
        ,#{score})
    </insert>
</mapper>

 测试方法:

@SpringBootTest
class StudentMapperTest {
    @Autowired
    private StudentMapper studentMapper;

    @Transactional
    @Test
    void addStu() {
        Student student = new Student();
        student.setUid(1);
        student.setName("张三");
        student.setScore(98);
        // 传入的实体对象中不包含 sex
        int result = studentMapper.addStu(student);
        System.out.println("插入成功:" + result);
    }
}

!!!使用时要注意区分属性和字段:

test 里要判断的是“属性” —— 来自实体类对象;

其他的是字段 —— 和数据库对应;


2. <trim> 标签:

        <trim>标签还会结合<if>标签一起使用,它有字面意思“修剪”的含义。

        当SQL语句中有很多个非必传参数时,一旦只传其中个别参数,就会导致残留逗号或括号等情况,导致SQL语句出现错误;<trim> 标签就会根据实际情况,去掉残留不必要的内容。

<trim>标签的四个参数:

        可根据场景添加

  • prefix:表示整个语句块,以prefix的值作为前缀
  • suffix:表示整个语句块,以suffix的值作为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀

下面演示:插入一条学生信息,但参数只传学生名,就会导致字段后面多出一个逗号,同时如果不穿参数,又会多出一对括号,借助 trim 来修改:

Mapper 接口: 

@Mapper
public interface StudentMapper {
    // 只插入学生姓名
    int addStuOnlyName(Student student);
}

SQL 语句:

    <insert id="addStuOnlyName">
        insert into student
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="uid != null and uid != '' ">
                    uid,
                </if>
                <if test="name != null and name != '' ">
                    name,
                </if>
                <if test="sex != null and sex != '' ">
                    sex,
                </if>
                <if test="score != null and score != '' ">
                    score
                </if>
            </trim>
        values
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="uid != null and uid != '' ">
                    #{uid},
                </if>
                <if test="name != null and name != '' ">
                    #{name},
                </if>
                <if test="sex != null and sex != '' ">
                    #{sex},
                </if>
                <if test="score != null and score != '' ">
                    #{score}
                </if>
            </trim>
    </insert>

单元测试:

@Test
    void addStuOnlyName() {
        Student student = new Student();
        student.setName("李四");
        int result = studentMapper.addStuOnlyName(student);
        System.out.println("插入成功:" + result);
    }

 


3. <where> 标签:

        直接借助示例演示:根据学生 uid 或 学生名 来查询一条学生信息,这里的两个查询条件都是非必传的。

        ① 如果查询时只给了其中一个条件,那么 where 后面连接时的 "and" 就会被多出来;

        ② 如果两个条件都不穿,那么 "where" 就会被多出来;

针对第一种情况:可以使用<trim> 标签去后缀的方式去掉 and,and 放在参数的后面;

针对第二种情况:解决办法很多种:

  1. where 后添加 1=1,and 放在每个条件参数前面,使用<trim>去前缀去掉and;
            (但这种写法很冗余,不是好办法)

  2. where 作为<trim>标签的前缀,只有<trim>里有代码,才会自动加上前缀 where,再按照去后缀的方式去掉 and;

  3. 使用 <where> 标签,专门解决这种场景:
        <where> 里面有内容,就会自动生成 where,没有就不生成。
    ​​​​​​​​​​​​​​   同时:如果有多出来的 and ,它也会
    按照去前缀的方式去掉

            

 


4. <set> 标签:

        <set> 标签用于修改场景,<set>标签也是包着所有参数,如果没有内容,就不加 set,但没有set语句对于 mysql 是错误的,所以至少要传一个参数

        <set> 会自动去掉多余的逗号

    <update id="updateStu">
        update student
        <set>
            <if test="uid != null and uid > 0">
                uid = #{uid},
            </if>
            <if test="name != null and name != '' ">
                name = #{name},
            </if>
            <if test="sex != null and sex != '' ">
                sex = #{sex},
            </if>
            <if test="score != null and score > 0">
                score = #{score}
            </if>
        </set>
        where uid = #{uid}
    </update>

5. <foreach> 标签:

        <foreach> 标签用于遍历传入的集合,它有五个可选项:

  1. collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
  2. item:遍历时的每⼀个对象
  3. open:语句块开头的字符串
  4. close:语句块结束的字符串
  5. separator:每次遍历的对象之间间隔的字符串
    // 根据 uid 批量删除
    int deleteByUids(List<Integer> uidList);
    <delete id="deleteByUids">
        delete from student
        where uid in
        <foreach collection="uidList" item="uid" open="(" close=")" separator=",">
            #{uid}
        </foreach>
    </delete>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@糊糊涂涂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值