第3章 动态SQL

article/2025/8/21 18:35:49

目录/Contents

    • 第3章 动态SQL
      • 学习目标
        • 掌握MyBatis中动态SQL元素的使用
        • 掌握MyBatis的条件查询操作
        • 掌握MyBatis的更新操作
        • 掌握MyBatis的复杂查询操作
      • 学习内容
        • 1 动态SQL中的元素
          • 1.1 使用动态SQL的好处
          • 1.2 动态SQL常用元素
        • 2 条件查询操作
          • 2.1 \<if>元素
          • 2.2 \<choose>、\<when>、\<otherwise>元素
          • 2.3 \<where>、\<trim>元素
        • 3 更新操作
          • 3.1 \<set>元素
        • 4 复杂查询操作
          • 4.1 \<foreach>元素的属性
          • 4.2 \<collection>属性的取值
          • 4.3 \<foreach>元素迭代数组
          • 4.4 \<foreach>元素迭代List
          • 4.5 \<foreach>元素迭代Map
        • 5 案例:学生信息查询系统
          • 5.1 需求
          • 5.2 项目搭建
          • 5.3 数据准备
          • 5.4 POJO类准备
          • 5.5 创建映射文件
          • 5.6 修改mybatis-config.xml核心配置文件
          • 5.7 编写MyBatisUtils工具类
          • 5.8 编写测试方法
          • 5.9 查看运行结果
          • 5.10 多条件查询案例结果分析
          • 5.11 修改映射文件
          • 5.12 编写测试方法

第3章 动态SQL

学习目标

掌握MyBatis中动态SQL元素的使用

掌握MyBatis的条件查询操作

掌握MyBatis的更新操作

掌握MyBatis的复杂查询操作

学习内容

1 动态SQL中的元素

1.1 使用动态SQL的好处

动态SQL是MyBatis的强大特性之一,MyBatis采用了功能强大的基于OGNL(Object Graph Navigation Language)的表达式来完成动态SQL。在MyBatis的映射文件中,开发人员可通过动态SQL元素灵活组装SQL语句,这在很大程度上避免了单一SQL语句的反复堆砌,提高了SQL语句的复用性。

1.2 动态SQL常用元素

在这里插入图片描述

2 条件查询操作

2.1 <if>元素

<if>元素的应用
在MyBatis中,<if>元素是最常用的判断元素,它类似于Java中的if语句,主要用于实现某些简单的条件判断。在实际应用中,我们可能会通过某个条件查询某个数据。例如,要查找某个客户的信息,可以通过姓名或者年龄来查找客户,也可以不填写年龄直接通过姓名来查找客户,还可以都不填写而查询出所有客户,此时姓名和年龄就是非必须条件。类似于这种情况,在MyBatis中就可以通过<if>元素来实现。

根据客户姓名和年龄组合条件查询客户信息,使用元素编写该组合条件的动态SQL。

<!– 该xml文件中只列出了if元素的动态SQL-->
<if test="username !=null and username !=‘’“>and username like concat('%',#{username}, '%')
</if>
<if test="jobs !=null and jobs !=‘’“>and jobs= #{jobs}
</if>
2.2 <choose>、<when>、<otherwise>元素

<choose><when><otherwise>使用场景
在使用<if>元素时,只要test属性中的表达式为true,就会执行元素中的条件语句,但是在实际应用中,有时只需要从多个选项中选择一个去执行。
例如下面的场景:“当客户名称不为空,则只根据客户名称进行客户筛选;当客户名称为空,而客户职业不为空,则只根据客户职业进行客户筛选。当客户名称和客户职业都为空,则要求查询出所有电话不为空的客户信息。”
针对上面情况,使用<if>元素进行处理是不合适的。MyBatis提供了<choose>、<when>、<otherwise>元素进行处理,这三个元素往往组合在一起使用,作用相当于Java语言中的if…else if…else。

       <!-- 只展示三个组合元素的部分-->
<choose><when test="username !=null and username !=''">and username like concat('%',#{username}, '%')</when><when test="jobs !=null and jobs !=''">and jobs= #{jobs}</when><otherwise>and phone is not null</otherwise>
</choose> 
2.3 <where>、<trim>元素

<where><trim>使用场景
在映射文件中,编写的SQL后面加入了“where 1=1”的条件的话,既保证了where后面的条件成立,又避免了where后面第一个词是and或者or之类的关键字。
例如下面这条Mybatis拼接出的SQL语句是不正确的。
select * from t_customer where and username like concat(‘%’,?, ‘%’) and jobs = #{jobs}
上述SQL语句中,where后直接跟的是and,这在运行时会报SQL语法错误,针对这种情况,可以使用MyBatis提供的元素和元素进行处理。

<where>元素

<select id="findCustomerByNameAndJobs" parameterType="com.itheima.pojo.Customer"resultType="com.itheima.pojo.Customer">select * from t_customer<where><if test="username !=null and username !=''">and username like concat('%',#{username}, '%')</if><if test="jobs !=null and jobs !=''">and jobs= #{jobs}</if></where></select>

上述代码配置中,<where>元素会自动判断由组合条件拼装的SQL语句,只有<where>元素内的某一个或多个条件成立时,才会在拼接SQL中加入where关键字,否则将不会添加;即使where之后的内容有多余的“AND”或“OR”,<where>元素也会自动将他们去除。

<trim>元素
元素用于删除多余的关键字,它可以直接实现元素的功能。元素包含4个属性。
prefix 指定给SQL语句增加的前缀
prefixOverrides 指定SQL语句中要去掉的前缀字符串
suffix 指定给SQL语句增加的后缀
suffixOverrides 指定SQL语句中要去掉的后缀字符串

     <select id="findCustomerByNameAndJobs" parameterType="com.itheima.pojo.Customer"resultType="com.itheima.pojo.Customer">select * from t_customer<trim prefix="where" prefixOverrides="and" ><if test="username !=null and username !=''">and username like concat('%',#{username}, '%')</if><if test="jobs !=null and jobs !=''">and jobs= #{jobs}</if></trim>
</select>

上述配置代码中,<trim>元素的作用是去除一些多余的前缀字符串,它的prefix属性代表的是语句的前缀(where),而prefixOverrides属性代表的是需要去除的前缀字符串(SQL中的“AND”或“OR”)。

3 更新操作

3.1 <set>元素

<set>元素使用场景
在Hibernate框架中,如果想要更新某一个对象,就需要发送所有的字段给持久化对象,然而在实际应用中,大多数情况下都是更新某一个或几个字段。如果更新的每一条数据都要将其所有的属性都更新一遍,那么执行效率是非常差的。为了解决更新数据的效率问题,MyBatis提供了元素。元素主要用于更新操作,它可以在动态SQL语句前输出一个SET关键字,并将SQL语句中最后一个多余的逗号去除。元素与元素结合可以只更新需要更新的字段。

<update id="updateCustomerBySet" parameterType="com.itheima.pojo.Customer">update t_customer <set><if test="username !=null and username !=''">username=#{username},</if><if test="jobs !=null and jobs !=''">  jobs=#{jobs},</if><if test="phone !=null and phone !=''">phone=#{phone},</if></set> where id=#{id}
</update> 

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

使用<trim>元素更新
除了使用<set>元素外,还可以通过<trim>元素来实现更新操作。其中, <trim>元素的prefix属性指定要添加的<trim>元素所包含内容的前缀为set,suffixOverrides属性指定去除的<trim>元素所包含内容的后缀为逗号 。

4 复杂查询操作

4.1 <foreach>元素的属性

在这里插入图片描述

4.2 <collection>属性的取值

在遍历参数时,<collection>属性的值是必须指定的。不同情况下,该属性的取值也是不一样的,主要有以下三种情况:List类型、数值类型、Map类型。
若入参为单参数且参数类型是一个List,collection属性值为list。
若入参为单参数且参数类型是一个数组,collection属性值为array。
若传入参数为多参数,就需要把参数封装为一个Map进行处理,collection属性值为Map。若传入参数为多参数,就需要把参数封装为一个Map进行处理,collection属性值为Map。

4.3 <foreach>元素迭代数组

<foeeach>实现入参为数组类型的遍历
例如,要从数据表t_customer中查询出id为1、2、3的客户信息,就可以利用数组作为参数,存储id的属性值1、2、3,并通过<foreach>元素迭代数组完成客户信息的批量查询操作。

在映射文件CustomerMapper.xml中,添加使用元素迭代数组执行批量查询操作的动态SQL。

<select id="findByArray" parameterType="java.util.Arrays"resultType="com.itheima.pojo.Customer">select * from t_customer where id in<foreach item="id" index="index" collection="array" open="(" separator="," close=")">	#{id}</foreach>
select>

在测试类MyBatisTest中,编写测试方法findByArrayTest()方法,实现客户信息的批量查询。

public void findByArrayTest() {SqlSession session = MyBatisUtils.getSession(); // 获取SqlSessionInteger[] roleIds = {2,3}; // 创建数组,封装查询id// 执行SqlSession的查询方法,返回结果集List<Customer> customers = session.selectList("com.itheima.mapper"+ ".CustomerMapper.findByArray", roleIds);	for (Customer customer : customers) {System.out.println(customer);}session.close();
}

执行MyBatisTest测试类的findByArrayTest()方法,控制台会输出结果。

在这里插入图片描述

4.4 <foreach>元素迭代List

元素迭代List的实现步骤具体如下。
在映射文件CustomerMapper.xml中,添加使用元素迭代List集合执行批量查询操作的动态SQL。

<select id="findByList" parameterType="java.util.Arrays"resultType="com.itheima.pojo.Customer">select * from t_customer where id in<foreach item="id" index="index" collection="list" open="(" separator="," close=")">#{id}</foreach>
</select>

在测试类MyBatisTest中,编写测试方法findByListTest(),用于批量查询客户信息。

public void findByListTest() {SqlSession session = MyBatisUtils.getSession();List<Integer> ids=new ArrayList<Integer>();ids.add(1);  ids.add(2);List<Customer> customers = session.selectList("com.itheima.mapper"+ ".CustomerMapper.findByList", ids);	for (Customer customer : customers) {System.out.println(customer);} session.close();
}

执行MyBatisTest测试类的findByListTest()方法,控制台会输出结果。

在这里插入图片描述

4.5 <foreach>元素迭代Map

下面通过一个案例演示如何使用元素迭代Map集合,实现多参数入参查询操作,案例具体实 现步骤如下。
在映射文件CustomerMapper.xml中,添加使用元素迭代Map集合执行批量查询操作的动态SQL。

<select id="findByMap" parameterType="java.util.Map"resultType="com.itheima.pojo.Customer">select * from t_customer where jobs=#{jobs} and id in<foreach item="roleMap" index="index" collection="id" open="(" 	separator="," close=")"> #{roleMap}</foreach>
</select>

在测试类MyBatisTest中,编写测试方法findByMapTest(),用于批量查询客户信息。

public void findByMapTest() {SqlSession session = MyBatisUtils.getSession();List<Integer> ids=new ArrayList<Integer>();ids.add(1); ids.add(2); ids.add(3);Map<String,Object> conditionMap = new HashMap<String, Object>();conditionMap.put(“id",ids); conditionMap.put("jobs","teacher");List<Customer> customers = session.selectList("com.itheima.mapper"+ ".CustomerMapper.findByMap", conditionMap);for (Customer customer : customers) { System.out.println(customer);}session.close();}

执行MyBatisTest测试类的findByMapTest()方法,控制台会输出结果。

在这里插入图片描述

5 案例:学生信息查询系统

5.1 需求

多条件查询
当用户输入的学生姓名不为空,则只根据学生姓名进行学生信息的查询;
当用户输入的学生姓名为空,而学生专业不为空,则只根据学生专业进行学生的查询;
单条件查询
查询出所有id值小于5的学生的信息;

5.2 项目搭建

创建一个名称为mybatis-demo03的项目

5.3 数据准备

在名称为mybatis的数据库中,创建一个dm_student表,并插入几条测试数据。

USE mybatis;
CREATE TABLE dm_student(id int(32) PRIMARY KEY AUTO_INCREMENT,name varchar(50),  major varchar(50),    sno varchar(16) );# 插入7条数据,其他省略
INSERT INTO dm_student VALUES ('1', '张三', '数学', '10001');
5.4 POJO类准备

创建持久化类Student,在类中声明id、name、major和sno属性,以及属性对应的getter/setter方法。

public class Student {// 定义变量主键id,姓名name,专业major,学号snoprivate Integer id;  private String name;    private String major;  private String sno;  // 省略getter/setter方法    @Overridepublic String toString() {returnStudent{+ “id=+ id +, name=‘” + name +,           major=" + major  + ", sno=" + sno + '}';}}
5.5 创建映射文件

创建映射文件StudentMapper.xml,编写根据学生姓名和专业组合成的条件查询学生信息的动态SQL。

<mapper namespace="com.itheima.mapper.StudentMapper"><select id=“findStudentByNameAndMajor” parameterType=com.itheima.pojo.Student” resultType="com.itheima.pojo.Student">select * from dm_student where 1=1	<choose><when test="name !=null and name !=''">and name like concat('%',#{name}, '%')</when><when test="major !=null and major !=''"> and major= #{major}</when><otherwise> and sno is not null</otherwise> </choose> </select>
</mapper>
5.6 修改mybatis-config.xml核心配置文件

在mybatis-config.xml映射文件的元素下添加StudentMapper.xml映射文件路径的配置,用于将StudentMapper.xml映射文件加载到程序中。具体配置代码如下。

<mapper resource="com/itheima/mapper/StudentMapper.xml"/>
5.7 编写MyBatisUtils工具类

创建MyBatisUtils工具类,该类用于封装读取配置文件信息的代码。

public class MyBatisUtils {private static SqlSessionFactory sqlSessionFactory = null;static {	 try {Reader reader = Resources.getResourceAsReader(“mybatis-config.xml”);	                           SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();} 	}public static SqlSession getSession() {return sqlSessionFactory.openSession();}
}
5.8 编写测试方法

在测试类MyBatisTest中,编写测试方法findStudentByNameOrMajorTest(),该方法用于根据学生姓名或专业查询学生信息。

public void findStudentByNameOrMajorTest() {SqlSession session=MyBatisUtils.getSession();Student student=new Student();student.setName("张三"); student.setMajor("英语");List<Student> students = session.selectList("com.itheima.mapper"+ ".StudentMapper.findStudentByNameAndMajor",student);for (Student student2 : students) {System.out.println(student2);}session.close();
}
5.9 查看运行结果

执行测试类MyBatisTest的findStudentByNameOrMajorTest()方法,控制台会输出结果。
在这里插入图片描述

5.10 多条件查询案例结果分析

由输出结果分析可知,在查询学生信息时,虽然同时传入了姓名和专业两个查询条件,但MyBatis所生成的SQL只是动态组装了学生姓名条件进行查询。如果将案例代码中的student.setName(“张三”)删除或者注释掉,使SQL只按专业进行查询。再次执行findStudentByNameOrMajorTest()方法,MyBatis生成的SQL会组装学生职业进行条件查询,同样查询出了学生信息。如果学生姓名和专业都为空,MyBatis的SQL便会组装元素中的SQL片段进行条件查询。

5.11 修改映射文件

在映射文件StudentMapper.xml中的元素下,编写查询所有id值小于5的学生信息的动态SQL。

<select id="findByList" parameterType="java.util.List"resultType="com.itheima.pojo.Student">select * from dm_student where id in<foreach item="id" index="index" collection="list"open="(" separator="," close=")">#{id}</foreach>
</select>
5.12 编写测试方法

在测试类MyBatisTest中,编写测试方法findByListTest()。

public void findByListTest() {SqlSession session = MyBatisUtils.getSession();List<Integer> ids=new ArrayList<Integer>();for(int i =1;i<5;i++){ ids.add(i);}List<Student> students = session.selectList("com.itheima.mapper"+ ".StudentMapper.findByList", ids);for (Student student : students) { System.out.println(student);}session.close();
}

http://chatgpt.dhexx.cn/article/3NUWKL3a.shtml

相关文章

Mybatis的特性详解——动态SQL

Mybatis的特性详解——动态SQL 前言一、动态sql的元素1.MyBatis if标签&#xff1a;条件判断2.MyBatis choose、when和otherwise标签3.MyBatis where标签4.MyBatis set标签5.MyBatis foreach标签6.MyBatis bind标签7.MyBatis trim标签仰天大笑出门去&#xff0c;我辈岂是蓬蒿人…

Java编程基础八股文(背诵版)

Java语言具有哪些特点&#xff1f; Java为纯面向对象的语言。它能够直接反应现实生活中的对象。 具有平台无关性。java利用Java虚拟机运行字节码&#xff0c;无论是在Windows、Linux还是MacOS等其它平台对Java程序进行编译&#xff0c;编译后的程序可在其它平台运行。 Java为…

Java编程基础篇

目录 计算机、程序和Java概述计算机组成 基本程序设计标识符数值数据类型格式化控制台输出输入输出重定向输入重定向输出重定向输入输出重定向方法重载变量的范围 数组声明数组变量创建数组初始化数组可边长参数二维数组静态变量、常量和方法静态变量 限定字符串StringBuilder和…

Java 基础编程入门

一、什么是Java Java是一种编程语言二、应用场景 非windows平台下互联网环境的开发首选三、Java语言特点 1、应用面广 2、简单易学(相对于C/C) 3、面向对象(更符合我们看待事物的特点) 4、跨平台(一处编译&#xff0c;处处运行) 5、多线程(提升系统性能) 单线…

JAVA的编程基础(上)

1. JAVA的基本语法 1.1 注释 单行注释&#xff1a;// 多行注释&#xff1a;/* */ 文档注释&#xff1a;/** */ 注意&#xff1a;单行注释可以嵌套&#xff0c;多行注释和文档注释不可以嵌套 1.2 关键字 含义&#xff1a;在编程语言中&#xff0c;已经被赋予一些特殊含义…

Java编程基础(1)

1.Java基本语法 &#xff08;1&#xff09;Java程序的基本格式&#xff1a; 修饰符 class 类名 { 程序代码 } 如果Java程序要运行&#xff0c;则必须要有main方法&#xff0c;main方法是程序运行的入口 格式&#xff1a; 修饰符 class 类名{ public static void main&…

Java编程基础之网络编程

网络编程 文章目录 网络编程概述C/S和B/S网络通信协议网络编程要素 IP类UDP协议数据传输发送端接收端udp数据传输丢失问题 TCP概述Socket客户端ServerSocket服务端Socket**服务器代码**客户端代码 文件上传实现客户端服务端多线程版 概述 C/S和B/S 网络通信协议 协议:protoco…

java编程基础(一)二进制

文章目录 二进制面试题bit 和 bytejava 中的 byte 类型java 中 byte 类型表示正数&#xff1a;java 中 byte 类型表示负数&#xff1a; 四种整数类型的最小和最大值二进制和十进制的互转练一练java 代码中直接写二进制字面值代码仓库 二进制 对于任何已知类型的传统计算机而言…

Java 基础

Java 基础知识点整理 Java 语言是一种优秀的编程语言&#xff0c;由 C 语言、C 语言发展而来。Java 语言提供了一些有效的新特性&#xff0c;使得使用 Java 比 C 更容易写出“无错代码”。 Java特性和优点 面向对象编程的思想&#xff0c;更简单有效&#xff0c;Java 省略了 …

Java编程基础②

Java编程基础 Java中的注释Java中的标识符Java中的关键字Java中的常量常量类型定义常量 java中的变量变量的定义及其数据类型变量的类型转换变量的作用域 java运算符算术运算符赋值运算符比较运算符逻辑运算符位运算符运算符的优先级 java流程控制语句if条件语句switch条件语句…

第二章 Java编程基础

第二章 Java编程基础 目录 一&#xff0e; Java基本语法1. 基本格式2. 注释3. 标识符4. 关键字5. 常量 二&#xff0e; 变量1. 定义2. 数据类型3. 整数类型变量4. 浮点类型变量5. 字符类型变量6. 布尔类型变量7. 类型转换8. 自动提升9. 变量作用域 三&#xff0e; 运算符1. 算数…

【JAVA】1.编程基础

1.Java基本语法 JAVA基本格式&#xff1a; 修饰符 class 类名{ 程序代码 } public class java {public static void main(String[] args) {System.out.println("HelloWorld"); } public static void main(String[] args) {} &#xff08;对于初学者来说这个部分必…

第二章Java编程基础

一、填空题 1&#xff0e;Java程序代码必须放在一个类中&#xff0c;类使用class关键词定义。 2&#xff0e;Java中的注释有三类&#xff0c;分别是单行注释、多行注释、文档注释。 3&#xff0e;Java语言中&#xff0c;int类型所占存储空间为4个字节。 4&#xff0e;用于比…

Java基础 —— 编程入门

一、比特(bit)和字节(byte) 一个0或者一个1存储为一个比特(bit)&#xff0c;是计算机中最小的存储单位。计算机中是最基本的存储单元是字节(byte)。 每个字节由8个比特构成。 计算机就是一系列的电路开关。每个开关存在两种状态:关(off)和开(on)。如果电路是开的&#xff0c;它…

第二章:JAVA编程基础

目录 一&#xff1a;Java的基本语法格式 二&#xff1a;Java中的变量与常量 三&#xff1a;Java中的运算符 四&#xff1a;选择结构语句 五&#xff1a;循环结构语句 六&#xff1a;数组 一&#xff1a;Java的基本语法格式 1&#xff1a;语法格式 [修饰符] class 类名{…

Java编程基础知识(一)

目录 一.Java的基本语法 1.Java的基本语法格式 2.Java中的注释 3.Java中的关键字 Java中的标识符 二.Java中的常量与变量 1.常量 2.变量 三.Java中的运算符 四.数据输入 一.Java的基本语法 1.Java的基本语法格式 编写Java程序必须先声明一个类&#xff0c;然后再类中…

Java编程基础

目录 第一篇、Java编程基础 ❀Java中的属性名词 ❀Java数据类型 ❀转义字符 ❀&& 和 & 与 || 和 | ❀方法 第二篇、Java面向对象编程 ❀类和对象 ❀面向过程和面向对象的区别 ❀面向对象程序设计的主要特性 ❀类和对象概述 ❀对象的内存结构 ❀垃圾空间…

java编程基础(入门级)(超级完整版)

java基础编程&#xff08;入门&#xff09; 01基础知识 1.计算机基础 【1】进制 A.十进制转化二进制 除以2&#xff0c;求余数&#xff0c;商继续除以2&#xff0c;一直到0为止&#xff0c;从底下往上得到结果。 B.二进制转化十进制 1 | 1 | 0 | 0 2 3 ∣ 2 2 ∣ 2 1 ∣ 2 …

UFBGA176+25 封装尺寸图

下图是UFBGA17625 封装规格的参数&#xff0c;根据下图的参数&#xff0c;即可制作UFBGA17625 的PCB封装

电阻的封装规格

1.直插式电阻 卧式直插电阻的封装形式为AXIAL-xx(比如 AXIAL-0.3)&#xff0c;0.3为焊盘中心距&#xff0c;单位是英寸&#xff0c;1 inch 25.4 mm 1000mil。 M型&#xff0c;电阻两端折弯。金属膜直插电阻功率-封装-尺寸对应表 封装尺寸(inch)对应长度&#xff08;mm&#…