MyBatis 动态SQL 详解!

在这里插入图片描述

目录

    • 一、 什么是动态 SQL?
    • 二、 为什么需要动态 SQL?
    • 三、 MyBatis 动态 SQL 标签
    • 四、 标签详解及示例
      • 1、 if 标签
      • 2、 choose、when、otherwise 标签
      • 3、 where 标签
      • 4、 set 标签
      • 5、 foreach 标签
      • 6、 sql、include 标签
    • 五、 总结

🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!

🌟了解 MyBatis 结果映射 请看 : MyBatis 结果映射详解!

其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等

如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning

这篇文章让我来好好讲解一下 MyBatis 的动态 SQL。

一、 什么是动态 SQL?

动态 SQL 是指在 SQL 语句中,根据不同的条件或参数,生成不同的 SQL 语句。 💡 在传统的 SQL 语句中,SQL 语句是固定的,无法根据不同的情况进行变化。 而动态 SQL 可以根据不同的条件,动态地拼接 SQL 语句,从而满足不同的查询需求。

MyBatis 提供了强大的动态 SQL 功能,允许你根据运行时条件构建 SQL 语句。这使得你可以编写更灵活、可维护的 SQL 映射。

二、 为什么需要动态 SQL?

  • 灵活性: 能够根据不同的条件生成不同的 SQL 语句,满足不同的查询需求。 🚀
  • 可维护性: 将 SQL 语句的逻辑与 Java 代码分离,使代码更易于维护。
  • 避免冗余: 避免编写大量的重复 SQL 语句,提高代码的复用性。
  • 性能优化: 可以根据不同的条件选择不同的索引,提高查询效率。 📈

三、 MyBatis 动态 SQL 标签

MyBatis 提供了一系列标签来构建动态 SQL。 以下是常用的标签及其用法:

  • <if>: 条件判断
  • <choose><when><otherwise>: 多条件选择
  • <where>: 智能 WHERE 子句
  • <set>: 智能 SET 子句
  • <foreach>: 循环遍历
  • <sql><include>: SQL 片段重用

四、 标签详解及示例

1、 if 标签

<if> 标签用于进行条件判断。 只有当 test 属性中的表达式为 true 时,才会将标签内的 SQL 片段添加到最终的 SQL 语句中。

<select id="findUsersByCondition" parameterType="map" resultType="User">SELECT * FROM usersWHERE 1=1 <!-- 避免第一个条件前出现 AND/OR --><if test="username != null and username != ''">AND username LIKE #{username}</if><if test="email != null and email != ''">AND email = #{email}</if>
</select>

解释:

  • id="findUsersByCondition":定义了一个名为 findUsersByCondition 的查询。
  • parameterType="map":指定参数类型为 map,这意味着你可以传递一个 Map 对象作为参数。
  • resultType="User":指定结果类型为 User 类。
  • WHERE 1=1:这是一个小技巧,用于避免在第一个条件前出现 ANDOR 关键字,导致 SQL 语法错误。 如果第一个 <if> 标签的条件成立,则会添加 AND 关键字,否则不会添加。
  • <if test="username != null and username != ''">:如果 username 不为 null 且不为空字符串,则添加 AND username LIKE #{username} 到 SQL 语句中。
  • <if test="email != null and email != ''">:如果 email 不为 null 且不为空字符串,则添加 AND email = #{email} 到 SQL 语句中。
  • #{username}#{email}:是 MyBatis 的参数占位符,用于将参数值安全地替换到 SQL 语句中。

Java 代码示例:

Map<String, Object> params = new HashMap<>();
params.put("username", "%john%");
params.put("email", "john.doe@example.com");List<User> users = sqlSession.selectList("findUsersByCondition", params);

生成的 SQL 语句示例:

如果 usernameemail 都不为空,则生成的 SQL 语句如下:

SELECT * FROM users
WHERE 1=1
AND username LIKE '%john%'
AND email = 'john.doe@example.com'

如果只有 username 不为空,则生成的 SQL 语句如下:

SELECT * FROM users
WHERE 1=1
AND username LIKE '%john%'

2、 choose、when、otherwise 标签

<choose> 标签类似于 Java 中的 switch 语句,用于多条件选择。 它包含多个 <when> 标签和一个 <otherwise> 标签。 MyBatis 会按照顺序评估每个 <when> 标签的 test 属性,如果有一个 <when> 标签的 test 属性为 true,则执行该 <when> 标签内的 SQL 片段,并跳过其他的 <when><otherwise> 标签。 如果所有的 <when> 标签的 test 属性都为 false,则执行 <otherwise> 标签内的 SQL 片段。

<select id="findUsersByCondition" parameterType="map" resultType="User">SELECT * FROM usersWHERE<choose><when test="username != null and username != ''">username LIKE #{username}</when><when test="email != null and email != ''">email = #{email}</when><otherwise>1=1 <!-- 如果没有条件,则查询所有用户 --></otherwise></choose>
</select>

解释:

  • <choose>:定义一个多条件选择结构。
  • <when test="username != null and username != ''">:如果 username 不为 null 且不为空字符串,则添加 username LIKE #{username} 到 SQL 语句中。
  • <when test="email != null and email != ''">:如果 email 不为 null 且不为空字符串,则添加 email = #{email} 到 SQL 语句中。
  • <otherwise>:如果 usernameemail 都为空,则添加 1=1 到 SQL 语句中,表示查询所有用户。

Java 代码示例:

Map<String, Object> params = new HashMap<>();
// params.put("username", "%john%"); // 只设置 username
// params.put("email", "john.doe@example.com"); // 只设置 emailList<User> users = sqlSession.selectList("findUsersByCondition", params);

生成的 SQL 语句示例:

如果 username 不为空,则生成的 SQL 语句如下:

SELECT * FROM users
WHERE
username LIKE '%john%'

如果 email 不为空,则生成的 SQL 语句如下:

SELECT * FROM users
WHERE
email = 'john.doe@example.com'

如果 usernameemail 都为空,则生成的 SQL 语句如下:

SELECT * FROM users
WHERE
1=1

3、 where 标签

<where> 标签用于智能地添加 WHERE 子句。 它会自动判断是否需要添加 WHERE 关键字,并自动去除多余的 ANDOR 关键字。

<select id="findUsersByCondition" parameterType="map" resultType="User">SELECT * FROM users<where><if test="username != null and username != ''">username LIKE #{username}</if><if test="email != null and email != ''">AND email = #{email}</if></where>
</select>

解释:

  • <where>:智能地添加 WHERE 子句。
  • 如果至少有一个 <if> 标签的条件成立,则 <where> 标签会自动添加 WHERE 关键字,并去除第一个 AND 关键字。
  • 如果所有的 <if> 标签的条件都不成立,则 <where> 标签不会添加任何内容。

Java 代码示例:

Map<String, Object> params = new HashMap<>();
params.put("username", "%john%");
params.put("email", "john.doe@example.com");List<User> users = sqlSession.selectList("findUsersByCondition", params);

生成的 SQL 语句示例:

如果 usernameemail 都不为空,则生成的 SQL 语句如下:

SELECT * FROM users
WHERE username LIKE '%john%'
AND email = 'john.doe@example.com'

如果只有 username 不为空,则生成的 SQL 语句如下:

SELECT * FROM users
WHERE username LIKE '%john%'

如果 usernameemail 都为空,则生成的 SQL 语句如下:

SELECT * FROM users

4、 set 标签

<set> 标签用于智能地添加 SET 子句。 它会自动判断是否需要添加 SET 关键字,并自动去除最后一个逗号。 通常用于 UPDATE 语句中。

<update id="updateUser" parameterType="User">UPDATE users<set><if test="username != null and username != ''">username = #{username},</if><if test="email != null and email != ''">email = #{email},</if></set>WHERE id = #{id}
</update>

解释:

  • <set>:智能地添加 SET 子句。
  • 如果至少有一个 <if> 标签的条件成立,则 <set> 标签会自动添加 SET 关键字,并去除最后一个逗号。
  • 如果所有的 <if> 标签的条件都不成立,则 <set> 标签不会添加任何内容。

Java 代码示例:

User user = new User();
user.setId(1);
user.setUsername("new_username");
// user.setEmail("new_email@example.com"); // 不更新 emailsqlSession.update("updateUser", user);

生成的 SQL 语句示例:

如果 username 不为空,则生成的 SQL 语句如下:

UPDATE users
SET username = 'new_username'
WHERE id = 1

如果 usernameemail 都不为空,则生成的 SQL 语句如下:

UPDATE users
SET username = 'new_username',
email = 'new_email@example.com'
WHERE id = 1

5、 foreach 标签

<foreach> 标签用于循环遍历集合。 它可以用于构建 IN 子句、批量插入等场景。

<select id="findUsersByIds" parameterType="list" resultType="User">SELECT * FROM usersWHERE id IN<foreach item="id" collection="list" open="(" separator="," close=")">#{id}</foreach>
</select>

解释:

  • item="id":指定集合中的每个元素的名字为 id
  • collection="list":指定要遍历的集合的名字为 list。 如果参数是数组,则 collection 属性的值为 array
  • open="(":指定循环开始时的字符串为 (
  • separator=",":指定每个元素之间的分隔符为 ,
  • close=")":指定循环结束时的字符串为 )
  • #{id}:表示集合中的每个元素的值。

Java 代码示例:

List<Integer> ids = Arrays.asList(1, 2, 3);List<User> users = sqlSession.selectList("findUsersByIds", ids);

生成的 SQL 语句示例:

SELECT * FROM users
WHERE id IN (1,2,3)

批量插入示例:

<insert id="insertUsers" parameterType="list">INSERT INTO users (username, email) VALUES<foreach item="user" collection="list" separator=",">(#{user.username}, #{user.email})</foreach>
</insert>

Java 代码示例:

List<User> users = new ArrayList<>();
users.add(new User("john", "john@example.com"));
users.add(new User("jane", "jane@example.com"));sqlSession.insert("insertUsers", users);

生成的 SQL 语句示例:

INSERT INTO users (username, email) VALUES
('john', 'john@example.com'),
('jane', 'jane@example.com')

6、 sql、include 标签

<sql> 标签用于定义 SQL 片段,<include> 标签用于引用 SQL 片段。 这可以提高代码的复用性。 ♻️

<sql id="userColumns">id, username, email
</sql><select id="findAllUsers" resultType="User">SELECT <include refid="userColumns"/> FROM users
</select><select id="findUserById" parameterType="int" resultType="User">SELECT <include refid="userColumns"/> FROM users WHERE id = #{id}
</select>

解释:

  • <sql id="userColumns">:定义一个名为 userColumns 的 SQL 片段,包含 id, username, email
  • <include refid="userColumns"/>:引用名为 userColumns 的 SQL 片段。

生成的 SQL 语句示例:

findAllUsers 生成的 SQL 语句:

SELECT id, username, email FROM users

findUserById 生成的 SQL 语句:

SELECT id, username, email FROM users WHERE id = 1

五、 总结

MyBatis 的动态 SQL 功能非常强大,可以根据不同的条件生成不同的 SQL 语句,从而满足不同的查询需求。 掌握这些标签的用法,可以编写更灵活、可维护的 SQL 映射。 🎉

一些建议:

  • 避免过度使用动态 SQL: 动态 SQL 虽然强大,但过度使用会增加代码的复杂性。 只有在必要的时候才使用动态 SQL。
  • 注意 SQL 注入: 在使用动态 SQL 时,要注意 SQL 注入的风险。 使用 MyBatis 的参数占位符 #{} 可以有效地防止 SQL 注入。
  • 测试: 编写充分的测试用例,确保动态 SQL 的正确性。 ✅

希望这篇文章能够帮助你理解 MyBatis 的动态 SQL。 😊

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

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

相关文章

阿里云服务器遭遇DDoS攻击有争议?

近年来&#xff0c;阿里云服务器频繁遭遇DDoS攻击的事件引发广泛争议。一方面&#xff0c;用户质疑其防御能力不足&#xff0c;导致服务中断甚至被迫进入“黑洞”&#xff08;清洗攻击流量的隔离机制&#xff09;&#xff0c;轻则中断半小时&#xff0c;重则长达24小时&#xf…

如何在Springboot的Mapper中轻松添加新的SQL语句呀?

在如今的软件开发界&#xff0c;Spring Boot可是非常受欢迎的框架哦&#xff0c;尤其是在微服务和RESTful API的构建上&#xff0c;真的是让人爱不释手&#xff01;今天&#xff0c;我们就来聊聊如何为Spring Boot项目中的Mapper添加新的SQL语句吧&#xff01;说起来&#xff0…

Qt 中 findChild和findChildren绑定自定义控件

在 Qt 中&#xff0c;findChild 和 findChildren 是两个非常实用的方法&#xff0c;用于在对象树中查找特定类型的子对象。这两个方法是 QObject 类的成员函数&#xff0c;因此所有继承自 QObject 的类都可以使用它们。当您需要查找并绑定自定义控件时&#xff0c;可以按照以下…

leecode第19天

15、三数之和 # 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c; # 同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 # 注意&#xff1a;答案中不可以包含重复…

2109. 向字符串添加空格

2109. 向字符串添加空格 题目链接&#xff1a;2109. 向字符串添加空格 代码如下&#xff1a; class Solution { public:string addSpaces(string s, vector<int>& spaces) {string res "";int j 0;//直接遍历即可for (int i 0;i < spaces.size();i…

Java Spring Boot 与前端结合打造图书管理系统:技术剖析与实现

目录 运行展示引言系统整体架构后端技术实现后端代码文件前端代码文件1. 项目启动与配置2. 实体类设计3. 控制器设计4. 异常处理 前端技术实现1. 页面布局与样式2. 交互逻辑 系统功能亮点1. 分页功能2. 搜索与筛选功能3. 图书操作功能 总结 运行展示 引言 本文将详细剖析一个基…

CSRF跨站请求伪造——入门篇【DVWA靶场low级别writeup】

CSRF跨站请求伪造——入门篇 0. 前言1. 什么是CSRF2. 一次完整的CSRF攻击 0. 前言 本文将带你实现一次完整的CSRF攻击&#xff0c;内容较为基础。需要你掌握的基础知识有&#xff1a; 了解cookie&#xff1b;已经安装了DVWA的靶场环境&#xff08;本地的或云的&#xff09;&am…

BT-Basic函数之首字母R

BT-Basic函数之首字母R 文章目录 BT-Basic函数之首字母Rrandomizercallremoterenamereportreport clearreport fault syndromereport isreport level isreport outreport usingre‑savere‑storereturnrevision$rexitrinitrli$rndrotaterpmcrpsrun randomize 以下是这段英文的…

CentOS 7 如何挂载ntfs的移动硬盘

CentOS 7 如何挂载ntfs的移动硬盘 前言一、查看硬盘并尝试挂载(提示无法挂载)二、yum安装epel-release提示yum被锁定三、强行终止yum的进程四、yum安装epel-release完成五、yum安装ntfs-3g六、此时可正常挂载NTFS硬盘 前言 CentOS 7默认情况下是不支持NTFS的文件系统&#xff…

面试常考简单操作

参考文章 面试常考简单操作 快速排序归并排序Dijkstra自定义排序交替打印奇偶数冒泡排序插入排序堆排序欧几里得算法求最大公约数单例模式的双重校验LRU 快速排序 public class Solution {private static int partition(int[] arr, int left, int right) {int temp arr[left]…

2025图像处理和深度学习国际学术会议(IPDL 2025)

重要信息 官网&#xff1a;www.IPDL.xyz 时间&#xff1a;2025年4月11-13日 地点&#xff1a;中国-成都 简介 随着深度学习和图像处理技术的迅速发展&#xff0c;相关技术的应用逐渐渗透到各个行业&#xff0c;如医疗影像分析、自动驾驶、安防监控和智能制造等。这些应用的…

RNN万能逼近定理证明

RNN万能逼近定理证明 RNN原理图和数学表达式RNN的万能逼近定理及其证明证明 RNN原理图和数学表达式 s t U h t − 1 W x t b ∈ R D h s_tUh_{t-1}Wx_tb\in\mathbb{R}^{D_h} st​Uht−1​Wxt​b∈RDh​ s t ∈ R D h s_t\in\mathbb{R}^{D_h} st​∈RDh​ U ∈ R D h D h U\…

算力重构营销生态:广电数字人 “造星“ 运动背后的智能革命

一、数字人 "造星" 运动&#xff1a;广电行业的智能觉醒 当陕西广电的虚拟主播 "小雅" 在柞水县融媒体中心实现日更 100 秒新闻&#xff0c;当湖北广电的 "王丹" 从新闻主播转型为城市文化 IP&#xff0c;一场由算力驱动的数字人 "造星&qu…

大数据Spark(五十六):Spark生态模块与运行模式

文章目录 Spark生态模块与运行模式 一、Spark生态模块 二、Spark运行模式 Spark生态模块与运行模式 一、Spark生态模块 Spark 生态模块包括&#xff1a;SparkCore、SparkSQL、SparkStreaming、StructuredStreaming、MLlib 和 GraphX。与 Hadoop 相关的整个技术生态如下所示…

Could not find artifact com.microsoft.sqlserver:sqljdbc4:jar:4.0 in central

具体错误 [ERROR] Failed to execute goal on project datalink-resource: Could not resolve dependencies for project com.leon.datalink:datalink-resource:jar:1.0.0: Could not find artifact com.microsoft.sqlserver:sqljdbc4:jar:4.0 in central (https://repo.maven…

运营商在网状态查询API接口如何对接?

运营商在网状态查询 API 接口是一种能够让开发者通过编程方式查询手机号码在运营商网络中当前状态的应用程序接口。该接口是一组规范和协议&#xff0c;允许第三方开发者通过特定的编程方式与运营商的系统进行交互&#xff0c;以查询手机号码在运营商网络中的当前状态。 运营商…

【JavaScript】---- 数组的交集,并集,差集的实现,以及Set对象的交集,并集,差集的详细介绍和使用

1. 前言 数组的交集,并集,差集的实现。其实本质来说都不算难,但是 Set 类直接实现这些方法,所以我们先自己实现一下,然后再讲解一下 Set 类的相同方法。 2. intersection 交集 用数学公式,交集被表示为: A ∩ B = { x ∈ A ∣ x ∈ B } A \cap B = \{x \in A \mid x…

青铜与信隼的史诗——TCP与UDP的千年博弈

点击下面图片带您领略全新的嵌入式学习路线 &#x1f525;爆款热榜 88万阅读 1.6万收藏 第一章 契约之匣与自由之羽 熔岩尚未冷却的铸造台上&#xff0c;初代信使长欧诺弥亚将液态秘银倒入双生模具。左侧模具刻着交握的青铜手掌&#xff0c;右侧则是展开的隼翼纹章。当星辰…

SpringBoot的日志框架

目录 默认日志框架 日志配置 更换日志框架 排除默认Logback 引入目标日志框架 添加配置文件 logback.xml SpringBoot的核心设计宗旨是约定大于配置&#xff0c;很多框架功能都给你默认加载和配置完成供你使用&#xff0c;但这就要求使用者对框架有一定的理解和改造能力&am…

今日行情明日机会——20250403

今日涨停的主要行业方向分析&#xff08;2025-04-03&#xff09; 1. 贸易战相关概念&#xff08;13家涨停&#xff09; 细分领域&#xff1a;外贸、稀土永磁、中日韩贸易、物流、港口。代表个股&#xff1a; 外贸&#xff1a;爱丽家居、派斯林、迪生力&#xff08;受特朗普宣布…