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

news2024/12/22 18:44:21


在上一篇的: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>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/786139.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

carla与g29联合调试(一)

前言&#xff1a; 之前做的carla与g29的联合调试&#xff0c;现在记录一下carla控制g29的实现流程。 一、总体通讯流程 主要实现为carla中车辆的方向盘转动带着g29跟着一起转动&#xff0c;使用ros通讯来实现这个过程。 二、具体实现流程 2.1首先确定g29的力反馈和转动 使…

基于LoRA微调部署Stable Diffusion【免费试用阿里云】

文章目录 Stable Diffusion介绍环境及资源准备过程注交互式建模&#xff08;PAI-DSW&#xff09;的试用在创建的工作空间中创建实例安装 Diffusers Stable Diffusion介绍 Stable Diffusion 是一种文本到图像的潜在扩散模型&#xff0c;由 Runway 和慕尼黑大学合作构建&#xf…

学习day52

1.关于 error Component name "School" should always be multi-word vue/multi-word-component-names 这里是因为脚手架的规范原因&#xff0c; 解决办法&#xff1a; 我是在vue.comfig.js文件中加入了一条配置&#xff0c;即 lintOnSave:false 整个文件的完整…

Spring Boot单元测试入门指南

Spring Boot单元测试入门指南 JUnit是一个成熟和广泛应用的Java单元测试框架&#xff0c;它提供了丰富的功能和灵活的扩展机制&#xff0c;可以帮助开发人员编写高质量的单元测试。通过JUnit&#xff0c;开发人员可以更加自信地进行重构、维护和改进代码&#xff0c;同时提高代…

(学习笔记)如何理解TCP是面向字节流的协议,UDP是面向报文的协议?

如何理解字节流&#xff1f; 之所以会说TCP是面向字节流的协议&#xff0c;UDP是面向报文的协议&#xff0c;是因为操作系统对TCP和UDP协议的发送方的机制不同&#xff0c;也就是问题原因在发送方 为什么UDP协议是面向报文的协议&#xff1f; 当用户消息通过UDP协议传输时&…

从原理到实践,分析 Redisson 分布式锁的实现方案(二)

上篇讲解了如何用 Redis 实现分布式锁的方案&#xff0c;它提供了简单的原语来实现基于Redis的分布式锁。然而&#xff0c;Redis作为分布式锁的实现方式也存在一些缺点。本文将引入Redisson来实现分布式锁。 一、Redisson是什么 Redisson是一个基于Redis的分布式Java框架。它提…

flutter(01) windows桌面版 编译环境安装指南

1 flutter环境安装 flutter官网参考&#xff1a;Install | Flutter 先下载flutter SDK>&#xff1a;flutter sdk下载--官网&#xff0c;之后解压到C:\Users\XXX\data&#xff08;这里以该路径为例&#xff0c;但可以为其他自定义路径&#xff09;目录下&#xff0c;在这里…

5.python设计模式【单例模式】

内容&#xff1a;保证一个类只有一个实例&#xff0c;并提供一个访问它的全局访问点角色&#xff1a; 单例&#xff08;Singleton&#xff09; UML图 举个例子&#xff1a; 需求&#xff1a;一个类只能实例化一个对象&#xff0c;不能实例化多个对象 from abc import abstract…

MATLAB与ROS联合仿真——ROS环境搭建及相关准备工作(上)

本篇文章主要介绍在安装完ROS后&#xff0c;在进行MATLAB与ROS联合仿真之前&#xff0c;需要进行的一些环境搭建以及准备工作&#xff0c;主要分为 创建ROS工作空间及功能包、必备功能包安装、安装Gazebo11、导入实验功能包至工作空间、安装Visual_Studio_Code(选做)、常用便捷…

python 面向对象 - 类 - 实例 - 类的使用 - self - init方法 - ATM面向对象实验

目录 面向过程和面向对象的对比&#xff1f; 面向对象 面向对象两个重要概念&#xff1a; > class&#xff08;类&#xff09;、实例 类&#xff1a;具有相同属性或方法的对象的集合 属性(变量)&#xff1a;编号、位置、余额 方法&#xff08;函数&#xff09;&#xf…

[论文阅读笔记24]Social-STGCNN: A Social Spatio-Temporal GCNN for Human Traj. Pred.

论文: 论文地址 代码: 代码地址 作者在这篇文章中直接用GNN对目标的轨迹时空特征进行建模, 并用时序CNN进行预测, 代替了训练难度较大和速度较慢的RNN类方法. 0. Abstract 行人轨迹预测是一个比较有挑战性的任务, 有着许多的应用. 一个行人的轨迹不仅是由自己决定的, 而且受…

Vue消息订阅与发布

引入第三方库pubsub.js: npm i pubsub-js Student.vue import pubsub from pubsub-jsmethods:{sendStudentName(){// this.$bus.$emit(hello,this.name)pubsub.publish(hello,666)}}, School.vue import pubsub from pubsub-jsmounted() {// console.log("school&quo…

【监控系统】Promethus的查询PromQL详解及案例实战

首先我们先来了解一下什么是PromQL。 PromQL是Prometheus提供了内置的数据查询语言PromQL&#xff0c;全称为Prometheus Query Language。PromQL是对指标(Metric)的查询/聚合/过滤的处理&#xff0c;Metric的语法格式 <metric name>{<label name><label value&…

优维低代码实践:添加构件

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

Mac 安装启动RabbitMq

使用HomeBrew安装 未安装的请参照我的这篇Mac安装HomeBrew文章 安装 执行命令 brew install rabbitmq启动方式 brew services start rabbitmq端口说明 端口用处5672RabbitMQ通讯端口&#xff0c;也就是连接使用的端口15672RabbbitMQ管理界面端口&#xff0c;需要开启Manage…

区块链实验室(10) - 实例说明PBFT的共识过程

前面描述过PBFT的仿真方式&#xff0c;见区块链实验室(3) – 用Go语言仿真PBFT算法&#xff0c;本文以上述仿真程序说明PBFT的共识过程。 为叙述方便&#xff0c;首先给出1个简化的网络&#xff0c;共4个节点&#xff0c;构成如下图所示的网络。这样的网络可以避免冗余的网络报…

ASEMI快恢复二极管SFP6012A参数, SFP6012A规格

编辑-Z SFP6012A参数描述&#xff1a; 型号&#xff1a;SFP6012A 最大峰值反向电压(VRRM)&#xff1a;1200V 平均整流正向电流(IF)&#xff1a;60A 非重复峰值浪涌电流(IFSM)&#xff1a;500A 工作接点温度和储存温度(TJ, Tstg)&#xff1a;-40 to 175℃ 最大热阻(RθJC…

链动2+1营销系统开发模式深度解析

链动21模式其实是一种针对快消品行业的营销模式&#xff0c;主要逻辑就是用薄利多销丰厚返利的方式来吸引客户&#xff0c;同时快速裂变团队。 这个模式的玩法也很简单&#xff0c;只有代理和老板两种身份&#xff0c;代理身份是用户购买499元产品可以解锁&#xff0c;同时享受…

【压测指南|压力测试核心性能指标及行业标准】

文章目录 压力测试核心性能指标及行业标准指标1&#xff1a;响应时间指标2&#xff1a;吞吐量&#xff08;TPS)指标3&#xff1a;失败率总结&#xff1a; 压力测试核心性能指标及行业标准 在做压力测试时&#xff0c;新手测试人员常常在看报告时倍感压力&#xff1a;这么多性能…

58,#include<algorithm>集合算法set_difference

功能描述&#xff1a; 求两个集合的差集 函数原型&#xff1a; set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest); //求两个集合的差集 //注意&#xff1a;两个集合必须是有序序列 //beg1 容器1开始迭代器 //end1 容器1结束迭代…