MyBatis 动态 SQL 使用详解
🌟 一、什么是动态 SQL?
动态 SQL 是指根据传入参数,动态拼接生成 SQL 语句,不需要写多个 SQL 方法。MyBatis 提供了 <if>、<choose>、<foreach>、<where> 等标签来实现这类操作
✅ 二、动态 SQL 的优点
| 优点 | 说明 |
|---|---|
| ✔️ 灵活 | 同一个 SQL 根据不同参数拼接不同条件(if / where),非常适合查询页面 |
| ✔️ 减少代码重复 | 比如模糊搜索功能,不再需要写多个 SQL 接口方法 |
| ✔️ 可读性强(配合 XML) | 结构清晰,尤其用 <where> / <set> / <foreach> |
| ✔️ SQL 控制权在开发者手中 | 和 Hibernate/JPA 相比,MyBatis 更易于优化复杂 SQL |
| ✔️ 易于维护多条件组合查询 | 如管理后台的搜索表单、动态筛选等功能 |
❌ 三、动态 SQL 的缺点
| 缺点 | 说明 |
|---|---|
| ❌ 编写略繁琐 | XML 写法需要嵌套多个标签,容易出错,特别是嵌套复杂条件时 |
| ❌ 可读性下降(过度嵌套) | 动态 SQL 太复杂时,XML 显得臃肿不易读 |
| ❌ 不利于 IDE 自动提示 | 逻辑写在 XML 中,IDE 很难做类型检查和智能提示 |
| ❌ SQL 拼接错误不易发现 | 某些条件组合可能拼错 SQL,运行期才报错 |
| ❌ 与注解风格冲突 | 注解方式不支持复杂的动态 SQL,只能用 XML 实现动态拼接 |
🛠️ 四、动态 SQL 适用场景
✅ 最适合的场景:
| 场景 | 举例 |
|---|---|
| 🔍 条件查询页面 | 多条件组合搜索,如:用户列表查询、订单筛选、日志检索 |
| 📋 后台管理系统 | 如 admin 页面支持 name、status、时间区间等动态条件 |
| 📊 报表查询系统 | 查询维度、范围、排序条件全是动态的 |
| 🧩 批量操作 | 如 IN 查询、批量更新、删除(用 <foreach>) |
| 📌 多字段更新 | UPDATE 语句中字段非空才更新(用 <set> 标签) |
❌ 不推荐使用的场景:
| 场景 | 原因 |
|---|---|
| 常规增删改查 | 逻辑简单,不需要动态拼接 |
| SQL 条件固定 | 写死 SQL 语句更清晰、维护方便 |
| 条件复杂但变化不大 | 建议写多个 SQL 方法,避免 XML 太臃肿 |
🔍 五、小结一张表
| 点评维度 | 动态 SQL 表现 |
|---|---|
| 灵活性 | ⭐⭐⭐⭐⭐ 超高 |
| 编写复杂度 | ⭐⭐⭐❌ 中等偏高 |
| 可维护性 | ⭐⭐⭐ 中等 |
| 性能控制 | ⭐⭐⭐⭐⭐ 好 |
| 推荐场景 | 多条件查询、批量操作 |
✨ 示例对比
✅ 使用动态 SQL:
<select id="searchUser" resultType="User">SELECT * FROM user<where><if test="name != null"> AND name LIKE CONCAT('%', #{name}, '%')</if><if test="age != null"> AND age = #{age}</if></where>
</select>
❌ 不使用动态 SQL(需要写多个方法):
<select id="findByName" ...>SELECT * FROM user WHERE name = #{name}</select>
<select id="findByAge" ...>SELECT * FROM user WHERE age = #{age}</select>
<select id="findByNameAndAge" ...>SELECT * FROM user WHERE name = #{name} AND age = #{age}</select>
🧩 MyBatis 动态 SQL 标签速查表
| 标签 | 作用 | 示例 | 注意事项 |
|---|---|---|---|
<if> | 条件判断 | <if test="name != null">AND name = #{name}</if> | test 支持 OGNL 表达式,如 != null && name != '' |
<choose> <when> <otherwise> | 分支选择(类似 switch-case) | 见下方示例 | 只能命中一个 <when>,类似 if…else |
<trim> | 自定义前缀、后缀、去掉多余的分隔符 | `<trim prefix=“WHERE” prefixOverrides="AND | OR "> … ` |
<where> | 自动加 WHERE 并去掉首个 AND/OR | <where><if test="...">AND ...</if></where> | 自动处理空条件时避免语法错误 |
<set> | 自动加 SET 并去掉多余逗号(用于 UPDATE) | <set><if test="...">name=#{name},</if></set> | 适用于动态更新字段 |
<foreach> | 遍历集合,构造 IN 语句、批量插入等 | 见下方示例 | 支持 list、array、Map,常用于 IN (...) |
<bind> | 创建一个变量,可用于字符串拼接等 | <bind name="pattern" value="'%' + name + '%'" /> | 常配合模糊查询使用 |
📚 示例合集
1️⃣ <if> 使用示例
<select id="selectUser" resultType="User">SELECT * FROM user<where><if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="age != null">AND age = #{age}</if></where>
</select>
2️⃣ <choose> / <when> / <otherwise> 示例
<select id="selectUser" resultType="User">SELECT * FROM user<where><choose><when test="name != null">AND name = #{name}</when><when test="age != null">AND age = #{age}</when><otherwise>AND status = 'active'</otherwise></choose></where>
</select>
3️⃣ <trim> 示例(手动 WHERE 拼接)
<select id="selectUser" resultType="User">SELECT * FROM user<trim prefix="WHERE" prefixOverrides="AND |OR "><if test="name != null">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></trim>
</select>
4️⃣ <set> 示例(动态更新)
<update id="updateUser">UPDATE user<set><if test="name != null">name = #{name},</if><if test="age != null">age = #{age},</if></set>WHERE id = #{id}
</update>
5️⃣ <foreach> 示例(IN 查询)
<select id="selectByIds" resultType="User">SELECT * FROM user WHERE id IN<foreach collection="idList" item="id" open="(" separator="," close=")">#{id}</foreach>
</select>
| 语法片段 | 含义 |
|---|---|
id="selectByIds" | 这是 Mapper 接口中方法对应的 SQL ID |
resultType="User" | 查询结果会映射成 User 类 |
collection="idList" | 传入的是一个集合参数名,比如一个 List<Integer> 类型的参数 |
item="id" | 遍历集合中的每个元素,当前元素命名为 id |
open="(" | 拼接 SQL 时,开头加一个左括号 ( |
separator="," | 每个参数之间用逗号隔开 |
close=")" | 最后一个参数后加上右括号 ) |
#{id} | 当前遍历元素的值,作为 SQL 参数传入(防 SQL 注入) |
6️⃣ <bind> 示例(模糊搜索)
<select id="searchByName" resultType="User"><bind name="pattern" value="'%' + name + '%'" />SELECT * FROM user WHERE name LIKE #{pattern}
</select>
| 部分 | 解释 |
|---|---|
<select id="searchByName"> | 定义一个 SQL 查询方法,ID 是 searchByName |
resultType="User" | 查询结果会封装成 User 对象 |
<bind name="pattern" value="'%' + name + '%'"/> | MyBatis 提供的 <bind> 标签: 动态创建一个变量 pattern,它的值是 '%xxx%' 这样的字符串,供后面 SQL 使用 |
value="'%' + name + '%'" | 拼接模糊匹配字符串(注意这里的 '%' 是字符串,需要加单引号) |
#{pattern} | MyBatis 会将 pattern 的值安全地替换进 SQL,防止 SQL 注入 |
📌 小技巧总结
| 目标 | 建议用法 |
|---|---|
| 多条件查询 | <where> 或 <trim> 配合 <if> |
| 动态更新字段 | <set> 配合 <if> |
| IN 查询 | <foreach> |
| 模糊搜索 | <bind> |
| 模拟 if…else | <choose> |
相关文章:
MyBatis 动态 SQL 使用详解
🌟 一、什么是动态 SQL? 动态 SQL 是指根据传入参数,动态拼接生成 SQL 语句,不需要写多个 SQL 方法。MyBatis 提供了 <if>、<choose>、<foreach>、<where> 等标签来实现这类操作 ✅ 二、动态 SQL 的优点…...
【重装系统】大白菜自制U盘装机,备份C盘数据,解决电脑启动黑屏/蓝屏
1. 准备 U 盘 U 盘容量至少 8G,备份 U 盘的数据(后期会格式化) 2. 从微软官网下载操作系统镜像 https://www.microsoft.com/zh-cn/software-download/windows11 3. 下载安装大白菜 https://www.alipan.com/s/33RVnKayUfY 4. 插入 U 盘&#…...
vue实现目录锚点且滚动到指定区域时锚点自动回显——双向锚点
最近在用vue写官网,别问我为什么用vue写官网,问就是不会jq。。。。vue都出现11年了。。。 左侧目录:点击时,右侧区域可以自动滚动到指定的位置。 右侧区域手动滚动时,左侧锚点可以自动切换到对应的目录上 从而实现…...
python——正则表达式
一、简介 在 Python 中,正则表达式主要通过 re 模块实现,用于字符串的匹配、查找、替换等操作。 二、Python的re模块 使用前需要导入: import re 三、常用方法 方法描述re.match(pattern, string)从字符串开头匹配,返回第一个匹…...
Flutter Invalid constant value.
0x00 问题 参数传入变量,报错! 代码 const Padding(padding: EdgeInsets.all(20),child: GradientProgressIndicator(value: _progress), ),_progress 参数报错:Invalid constant value. 0x01 原因 这种情况,多发生于ÿ…...
libev实现Io复用及定时器事件服务器
客户端和服务器都绑定在了enp2s0网卡,需要SERVER_IP和SERVER_PORT改为其ip,注意不能是127.0.0.1,因为这个是lo虚拟网口。 安装libev sudo apt-get install libev-dev客户端: #include <iostream> #include <string>…...
【精品PPT】2025固态电池知识体系及最佳实践PPT合集(36份).zip
精品推荐,2025固态电池知识体系及最佳实践PPT合集,共36份。供大家学习参考。 1、中科院化学所郭玉国研究员:固态金属锂电池及其关键材料.pdf 2、中科院物理所-李泓固态电池.pdf 3、全固态电池技术研究进展.pdf 4、全固态电池生产工艺.pdf 5、…...
如何计算设备电池工作时长?
目录 【mAh(毫安时)计算方法】 【Wh(瓦时)计算方法】 【为什么仅用电流(mA)和时间(h)就能计算电池使用时长(mAh)?】 1. mAh 的本质是“电荷量…...
抽象类及其特性
目录 1、概念2、语法3、特性4、作用 1、概念 在面向对象中,所有对象都是通过类来描述的,但是并不是所有的类都可以用来描述对象。比如下述例子中的 Animal 类,Dog 类和 Cat 类是 Animal 类的子类,可以分别描述小狗和小猫…...
【教程】xrdp修改远程桌面环境为xfce4
转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 目录 xfce4 vs GNOME对比 配置教程 1. 安装 xfce4 桌面环境 2. 安装 xrdp 3. 配置 xrdp 使用 xfce4 4. 重启 xrdp 服务 5. 配置防火墙ÿ…...
利用python从零实现Byte Pair Encoding(BPE):NLP 中的“变形金刚”
BPE:NLP 界的“变形金刚”,从零开始的奇幻之旅 在自然语言处理(NLP)的世界里,有一个古老而神秘的传说,讲述着一种强大的魔法——Byte Pair Encoding(BPE)。它能够将普通的文本“变形…...
部署redis cluster
一。在所有的主机里面设置密码和文件地址 vi /etc/redis/6379.conf 注释:登陆则要使用auth 123456才可以进入redis 配置文件地址和超时时间 二。创建集群:上面主机为master,下面为slave,master和slave会随机分配 先写主节点&…...
Android 11 (API 30) 及更高版本中,查询的特定应用商店包,无需动态请求权限处理
在 Android 11 (API 30) 及更高版本中,通过在 AndroidManifest.xml 中添加 <queries> 元素声明需要查询的特定应用商店包名后: 1. 不需要额外请求权限 (如 QUERY_ALL_PACKAGES )即可查询这些应用的安装状态 2. 这是 Googl…...
基于springboot钻孔数据管理系统的设计与实现(源码+lw+部署文档+讲解),源码可白嫖!
摘要 本钻孔数据管理系统采用B/S架构,数据库是MySQL,网站的搭建与开发采用了先进的Java语言、Hadoop、数据可视化技术进行编写,使用了Spring Boot框架。该系统从两个对象:由管理员和用户来对系统进行设计构建。用户主要功能包括&…...
SpringBoot和微服务学习记录Day2
微服务 微服务将单体应用分割成更小的的独立服务,部署在不同的服务器上。服务间的关联通过暴露的api接口来实现 优点:高内聚低耦合,一个模块有问题不影响整个应用,增加可靠性,更新技术方便 缺点:增加运维…...
4.9复习记
1.地宫取宝--记忆化搜索,可以先写void dfs,然后在改成ll 形式的,边界条件return 0/1; 记忆化数组与dfs元素保持一致,记得记忆化剪枝 这个题特殊在value可能是0,不取的时候应该记为-1 https://mpbeta.cs…...
LinuxSocket套接字编程
1.介绍函数使用 1.创建套接字 int socket(int domain, int type, int protocol); domain:指定协议族,如AF_INET(IPv4)或AF_INET6(IPv6)。 type:指定套接字类型,如SOCK_DGRAM&#…...
动态科技感html导航网站源码
源码介绍 动态科技感html导航网站源码,这个设计完美呈现了科幻电影中的未来科技界面效果,适合展示技术类项目或作为个人作品集的入口页面,自适应手机。 修改卡片中的链接指向你实际的HTML文件可以根据需要调整卡片内容、图标和颜色要添加更…...
Java进阶版线程池(超详细 )
线程池 线程池工具类 Executors Executors 是 Java 提供的一个工具类,它包含了多个静态方法,能够方便地创建不同类型的线程池。 newFixedThreadPool 创建一个固定大小的线程池,线程池中的线程数量固定,当有新任务提…...
每日算法:洛谷U535992 J-C 小梦的宝石收集(双指针、二分)
题目描述 小梦有 n 颗能量宝石,其中第 i 颗的能量为 ai,但这些能量宝石十分不稳定,随时有可能发生崩坏,导致他们全部消失! 小梦想要留住宝石们,不希望他们发生崩坏,同时他发现:如…...
YOLOv11训练中精准率召回率与mAP@0.5的动态变化分析
目标检测模型的训练过程涉及多个关键性能指标和损失函数的变化,这些数据能够直观反映模型的收敛速度、最终精度以及改进效果。本文旨在通过绘制YOLOv11模型在训练过程中的精准率(Precision)、召回率(Recall)、mAP0.5 、…...
Java常用工具算法-6--秘钥托管云服务AWS KMS
前言: 之前我们介绍了一些常用的加密算法(如:对称加密AES,非对称加密RSA,ECC等),不论是哪一种都需要涉及到秘钥的管理。通常的做法都是把秘钥放到配置文件中进行配置,但是对于一些高…...
11. Langchain输出解析(Output Parsers):从自由文本到结构化数据
引言:从"自由发挥"到"规整输出" 2025年某金融机构的合同分析系统升级前,AI生成的合同摘要需人工二次处理达47分钟/份。引入LangChain结构化解析后,处理时间缩短至3分钟。本文将详解如何用LangChain的解析器,…...
docker stack常用命令
1、Docker Stack介绍 Docker Stack管理swarm堆栈与Swarm协调器配合使用,是Docker Swarm环境中用于管理一组相关服务的工具。它使得在Swarm集群中部署、管理和扩展一组相互关联的服务变得简单。主要用于定义和编排容器化应用的多个服务。以下是Docker Stack的一些关…...
python reportlab模块----操作PDF文件
reportlab模块----操作PDF文件 一. 安装模块二. reportlab相关介绍三. 扩展canvas类四. 水平写入完整代码五. 垂直写入完整代码 一. 安装模块 pip install reportlab二. reportlab相关介绍 # 1. letter 生成A4纸张尺寸 from reportlab.lib.pagesizes import letter print(let…...
解锁基因密码之重测序(从测序到分析)
在生命科学的奇妙世界中,基因恰似一本记录着生命奥秘的“天书”,它承载着生物体生长、发育、衰老乃至疾病等一切生命现象的关键信息。而重测序技术,则是开启基因“天书”奥秘的一把神奇钥匙。 试想,你手中有一本经典书籍的通用版…...
TQTT_KU5P开发板教程---QSFP25G光口回环测试
文档实现功能介绍 本文档通过一个叫做ibert的IP,实现25G光口回环测试例子。工程新建方法请参考文档《流水灯》,其中只是将文件名进行修改。 Vivado 起始页(或 file-->Project-->New 创建新工程(Create New Project) 向导起始页面 点…...
JVM虚拟机篇(七):JVM垃圾回收器全面解析与G1深度探秘及四种引用详解
JVM垃圾回收器全面解析与G1深度探秘及四种引用详解 JVM虚拟机(七):JVM垃圾回收器全面解析与G1深度探秘及四种引用详解一、JVM有哪些垃圾回收器1. Serial回收器2. ParNew回收器3. Parallel Scavenge回收器4. Serial Old回收器5. Parallel Old回…...
柑橘病虫害图像分类数据集OrangeFruitDaatset-8600
文章目录 1. 前言2. 数据类别介绍3. 数据集地址 1. 前言 柑橘,作为水果界的 “宠儿”,不仅以其酸甜可口的味道深受大众喜爱,更是在全球水果产业中占据着举足轻重的地位。无论是早餐中的一杯橙汁,还是下午茶里的柑橘甜点ÿ…...
深度学习总结(4)
张量积 张量积(tensor product)或点积(dot product)是最常见且最有用的张量运算之一。注意,不要将其与逐元素乘积(*运算符)弄混。在NumPy中,使用np.dot函数来实现张量积,…...
