MyBatis 动态查询语句详解:让 SQL 更灵活可控

在日常的数据库操作中,我们经常会遇到需要根据不同条件拼接 SQL 语句的场景。比如查询用户时,可能需要根据姓名、年龄、性别等多个条件进行筛选,而这些条件往往是动态变化的 —— 有时需要按姓名查,有时需要按年龄查,有时又需要组合多个条件。如果手动拼接 SQL,不仅容易出错,还会让代码变得臃肿难维护。MyBatis 的动态查询语句正是为解决这一问题而生,它能根据参数的不同自动拼接 SQL 片段,让 SQL 编写更加灵活高效。

一、动态查询的核心价值

动态查询是 MyBatis 的核心特性之一,它允许我们在 XML 映射文件或注解中,通过一系列标签控制 SQL 片段的拼接逻辑。其核心价值体现在三个方面:

  • 减少冗余代码:无需为不同条件组合编写大量重复的 SQL 语句。

  • 避免 SQL 注入风险:MyBatis 的动态标签会自动处理参数拼接,比手动字符串拼接更安全。

  • 提升代码可读性:将条件判断逻辑与 SQL 语句分离,让业务逻辑更清晰。

举个简单的例子:查询用户列表时,可能需要根据姓名(name)和年龄(age)筛选。如果没有动态查询,我们可能需要编写 3 条 SQL(只查 name、只查 age、同时查 name 和 age);而有了动态查询,1 条 SQL 就能搞定所有场景。

二、常用动态查询标签详解

MyBatis 提供了一套完整的动态 SQL 标签,涵盖了大多数条件判断场景。下面介绍最常用的几个标签及其用法。

1. <if>:条件判断的基础

<if>标签是动态查询中最常用的标签,用于根据参数值决定是否拼接某个 SQL 片段。其语法如下:

<if test="条件表达式">SQL片段
</if>

示例:根据姓名和年龄查询用户

<select id="selectUser" resultType="User">SELECT * FROM userWHERE 1=1<if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="age != null">AND age = #{age}</if>
</select>

这里的WHERE 1=1是为了避免当所有<if>条件都不满足时,SQL 出现WHERE后无内容的语法错误。当name不为空时,会拼接AND name LIKE ...;当age不为空时,会拼接AND age = ...

2. <choose>+<when>+<otherwise>:多条件分支选择

当需要实现 “多条件选其一” 的逻辑时,可以使用<choose>标签(类似 Java 中的switch),配合<when>(类似case)和<otherwise>(类似default)标签使用。

示例:优先按姓名查询,若姓名为空则按年龄查询,否则查询所有

<select id="selectUserByCondition" resultType="User">SELECT * FROM user<where><choose><when test="name != null and name != ''">name LIKE CONCAT('%', #{name}, '%')</when><when test="age != null">age = #{age}</when><otherwise>1=1  <!-- 当所有条件都不满足时,查询所有数据 --></otherwise></choose></where>
</select>

<where>标签会自动处理 SQL 片段开头的ANDOR,避免语法错误。比如当第一个<when>条件满足时,拼接的name LIKE ...前不会有多余的AND

3. <trim>:自定义 SQL 片段拼接规则

<trim>标签可以通过属性自定义 SQL 片段的前缀、后缀,以及需要去掉的前缀或后缀字符,比<where>更灵活。常用属性:

  • prefix:给拼接的 SQL 片段添加前缀

  • suffix:给拼接的 SQL 片段添加后缀

  • prefixOverrides:去掉片段开头的指定字符

  • suffixOverrides:去掉片段结尾的指定字符

示例:用<trim>实现<where>的功能

<select id="selectUser" resultType="User">SELECT * FROM user<trim prefix="WHERE" prefixOverrides="AND | OR"><if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="age != null">AND age = #{age}</if></trim>
</select>

<trim>内部有内容时,会添加WHERE前缀,并去掉开头的ANDOR,效果与<where>一致。

4. <foreach>:遍历集合参数

当需要处理批量操作(如IN查询、批量插入)时,<foreach>标签非常有用。它可以遍历数组或集合,将元素拼接成 SQL 片段。常用属性:

  • collection:指定要遍历的集合参数名(如listarray@Param定义的名称)

  • item:遍历过程中每个元素的别名

  • index:遍历索引(可选)

  • open:片段开头的字符

  • close:片段结尾的字符

  • separator:元素之间的分隔符

示例 1:批量查询(IN 语句)

<select id="selectUserByIds" resultType="User">SELECT * FROM userWHERE id IN<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach>
</select>

ids[1,2,3]时,会拼接成WHERE id IN (1,2,3)

示例 2:批量插入

<insert id="batchInsertUser">INSERT INTO user (name, age) VALUES<foreach collection="list" item="user" separator=",">(#{user.name}, #{user.age})</foreach>
</insert>

list包含 3 个 User 对象时,会拼接成INSERT INTO user (name, age) VALUES (?,?), (?,?), (?,?)

5. <set>:更新语句的动态处理

在更新操作中,<set>标签用于动态拼接SET子句,会自动去掉多余的逗号。

示例:动态更新用户信息

<update id="updateUser">UPDATE user<set><if test="name != null and name != ''">name = #{name},</if><if test="age != null">age = #{age},</if></set>WHERE id = #{id}
</update>

nameage都不为空时,会拼接成UPDATE user SET name = ?, age = ? WHERE id = ?,自动去掉age = ?后的逗号。

三、实战案例:综合运用动态标签

下面通过一个复杂案例,展示如何综合运用上述标签实现多条件组合查询。

需求:查询商品列表,支持按分类(category)、价格范围(minPrice、maxPrice)、是否库存(hasStock)筛选,且支持排序(sortField、sortType)。

Mapper 接口

List<Product> selectProducts(@Param("category") String category,@Param("minPrice") BigDecimal minPrice,@Param("maxPrice") BigDecimal maxPrice,@Param("hasStock") Boolean hasStock,@Param("sortField") String sortField,@Param("sortType") String sortType
);

XML 映射文件

<select id="selectProducts" resultType="Product">SELECT * FROM product<trim prefix="WHERE" prefixOverrides="AND | OR"><if test="category != null and category != ''">AND category = #{category}</if><if test="minPrice != null">AND price >= #{minPrice}</if><if test="maxPrice != null">AND price <= #{maxPrice}</if><if test="hasStock != null">AND stock > 0</if></trim><if test="sortField != null and sortField != '' and sortType != null">ORDER BY ${sortField} ${sortType}  <!-- 排序字段用${},注意SQL注入风险 --></if>
</select>

说明

  • <trim>处理查询条件,避免多余的AND

  • <if>判断每个筛选条件是否生效

  • 排序部分通过<if>控制是否拼接ORDER BY,注意排序字段使用${}(因为#{}会加引号,导致语法错误),但需确保sortFieldsortType是可信参数,避免 SQL 注入。

四、注意事项与最佳实践

  1. 参数判断的细节
  • 字符串判断:test="name != null and name != ''"(先判断非空,再判断非空字符串)

  • 数字判断:test="age != null"(无需判断空字符串)

  • 布尔值判断:test="hasStock != null and hasStock"(直接用参数名判断 true/false)

  1. SQL 注入风险
  • 动态 SQL 中,#{}会自动加引号,适合参数值;${}直接拼接 SQL,适合表名、字段名等,但需严格校验参数,避免注入。

  • 排序、分组等场景需用${}时,建议限制可选值(如sortField只能是idprice等已知字段)。

  1. 代码可读性
  • 复杂动态 SQL 建议拆分到 XML 文件,而非注解中

  • 给参数添加@Param注解,避免使用arg0arg1

  • 合理使用换行和缩进,保持 SQL 结构清晰

  1. 性能优化
  • 避免过度复杂的动态 SQL,否则可能影响数据库优化器生成执行计划

  • 频繁执行的动态 SQL,建议通过 MyBatis 的二级缓存缓存结果

五、总结

MyBatis 的动态查询语句通过<if><choose><foreach>等标签,完美解决了 SQL 条件动态拼接的问题,让开发者能更专注于业务逻辑而非 SQL 语法细节。掌握这些标签的用法,不仅能减少代码量,还能提升系统的灵活性和可维护性。

在实际开发中,建议结合具体业务场景选择合适的标签,同时注意参数校验和 SQL 注入风险,让动态 SQL 成为提升开发效率的利器而非隐患。

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

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

相关文章

Java基础语法three

一、一维数组一维数组初始化数据类型[] 数组名new 数据类型[数组长度]//动态初始化数据类型[] 数组名new 数据类型[]{值}//静态初始化数据类型[] 数组名{值}数组长度一旦确定&#xff0c;就不可更改。数组是序排序&#xff1b;数组属于引用数据类型的变量&#xff0c;数组的元素…

【数据结构】排序算法全解析:概念与接口

1.排序的概念及其运用 1.1 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的…

在 CentOS 7 上使用 LAMP 架构部署 WordPress

CentOS 7 LAMP 架构部署 WordPress全步骤本文将详细介绍如何在 CentOS 7 系统上通过 LAMP&#xff08;Linux Apache MariaDB PHP&#xff09;架构部署 WordPress 博客平台。 在CentOS 7上基于LAMP架构部署WordPress 一、系统基础配置 1. 修改主机名&#xff08;本机IP&#…

Node.js导入MongoDB具体操作

在Node.js应用程序中&#xff0c;导入MongoDB是一项常见任务。本文将详细介绍如何在Node.js中连接和操作MongoDB数据库&#xff0c;包括安装必要的包、配置连接、执行基本的CRUD操作等步骤。1. 安装必要的包首先&#xff0c;确保你已经安装了Node.js和npm。然后&#xff0c;通过…

HTML--pre标签的作用

原文网址&#xff1a;HTML--pre标签的作用-CSDN博客 简介 本文介绍HTML里pre标签的作用。 <pre> 元素表示预定义格式文本。里边的文本会保留原格式&#xff0c;以等宽字体的形式展现出来&#xff0c;文本中的空白符&#xff08;比如空格和换行符&#xff09;都会显示出…

机器学习--数据预处理

目录 一、数据清洗&#xff1a;让数据纯净如新 1、缺失值处理&#xff1a; 2、异常值处理 3、重复值处理 二、数据变换&#xff1a;重塑数据的 “形状” 1、归一化 2、标准化 三、总结与展望 机器学习小白必看&#xff1a;数据预处理实战笔记 最近投身于机器学习的学习…

Python 数据可视化:Matplotlib 与 Seaborn 实战

Python 数据可视化&#xff1a;Matplotlib 与 Seaborn 实战​​​​在当今数据驱动的时代&#xff0c;数据可视化成为了理解和传达数据信息的关键手段。Python 作为一门强大的编程语言&#xff0c;拥有丰富的数据可视化库&#xff0c;其中 Matplotlib 和 Seaborn 尤为突出。本文…

计算机网络技术学习-day4《路由器配置》

目录 一、路由器基础认知 1. 路由器的核心功能 2. 路由器与交换机的区别 二、路由器配置基础操作 1. CLI&#xff08;命令行界面&#xff09;模式体系 2. 基础配置命令示例 &#xff08;1&#xff09;基础信息配置 &#xff08;2&#xff09;接口IP地址配置&#xff08;…

IDEA(十四) IntelliJ Idea 常用快捷键(Mac)

目录准备&#xff1a;Mac键盘符号和修饰键说明一、编辑类快捷键二、Search/Replace&#xff08;查询/替换&#xff09;三、编译、运行四、debug 调试五、Navigation&#xff08;导航&#xff09;六、Refactoring&#xff08;重构&#xff09;七、VCS/Local History八、Live Tem…

八月月报丨MaxKB在教育及教学科研领域的应用进展

在2025年5月的“MaxKB用户应用月度报告”中&#xff0c;我们对MaxKB开源智能体平台在教育行业的典型应用场景进行了总结。MaxKB在教育行业的应用主要集中在教学辅助、学术研究、校园服务、行政办公、财务管理、招生等场景。 目前&#xff0c;“DeepSeekMaxKB”的组合正在被包括…

一周学会Matplotlib3 Python 数据可视化-绘制自相关图

锋哥原创的Matplotlib3 Python数据可视化视频教程&#xff1a; 2026版 Matplotlib3 Python 数据可视化 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 课程介绍 本课程讲解利用python进行数据可视化 科研绘图-Matplotlib&#xff0c;学习Matplotlib图形参数基本设置&…

第三十三天(信号量)

非常非常非常.....的重要在共享内存的代码里面p1.c实质是有问题lt._flag 1;//这里先置1if(c Q)sprintf(lt._buf,"quit");elsesprintf(lt._buf,"大家好&#xff0c;%d 我系渣渣辉. %d 是兄弟就来砍我吧!!! %d",i,i1,i2);while(*((int *)shmptr));//如果别…

Scikit-learn通关秘籍:从鸢尾花分类到房价预测

点击 “AladdinEdu&#xff0c;同学们用得起的【H卡】算力平台”&#xff0c;H卡级别算力&#xff0c;按量计费&#xff0c;灵活弹性&#xff0c;顶级配置&#xff0c;学生专属优惠。 决策树/SVM/KNN算法对比 模型评估指标解析 读者收获&#xff1a;掌握经典机器学习全流程 …

rsync + inotify 数据实时同步

rsync inotify 数据实时同步 一、rsync简介 rsync是linux系统下的数据镜像备份工具。使用快速增量备份工具Remote Sync可以远程同步&#xff0c; 支持本地复制&#xff0c;或者与其他SSH、rsync主机同步 二、rsync三种命令 Rsync的命令格式常用的有以下三种&#xff1a;&#…

Linux基础介绍-3——第一阶段

文章目录一、进程管理1.1 进程的基本概念1.2 常见管理命令1.3 进程优先级调整&#xff1a;nice 与 renice二、软件包管理三、防火墙管理四、shell脚本五、xshell链接kali一、进程管理 1.1 进程的基本概念 进程是程序的动态执行实例&#xff0c;每个进程都有唯一的 PID&#x…

python 可迭代对象相关知识点

1. 什么是可迭代对象 (Iterable) 在 Python 里&#xff0c;可迭代对象指的是&#xff1a; &#x1f449; 能够一次返回一个元素的对象&#xff0c;可以被 for 循环遍历。 常见的可迭代对象有&#xff1a; 序列类型&#xff1a;list、tuple、str集合类型&#xff1a;set、dict&a…

ijkplayer Android 编译

一、下载编译库文件1.1 编译库文件环境&#xff1a;ubuntu 20.04 版本liangtao:ffmpeg$lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.6 LTS Release: 20.04 Codename: focal1.2 项目源码下载使用 git 下载 ijkplayer&#…

snn前向推理时间计算(处理器实现)

公式 Tinf(1−sparsity)number of synapsesnumber of sub-processorsSIMD ways T_{\text{inf}} \frac{(1-\text{sparsity})\times \text{number of synapses}} {\text{number of sub-processors}\times \text{SIMD ways}} Tinf​number of sub-processorsSIMD ways(1−sparsity…

Linux------《操作系统全景速览:Windows·macOS·Linux·Unix 对比及 Linux 发行版实战指南》

&#xff08;一&#xff09;常见操作系统&#xff08;system&#xff09;电脑&#xff1a;Windows,Macos,Linux,UnixWindows&#xff1a;微软公司开发的一款桌面操作系统&#xff08;闭源系统&#xff09;。版本有dos&#xff0c;win98&#xff0c;win NT&#xff0c;win XP , …

Three.js 初级教程大全

本文档旨在为初学者提供一个全面的 Three.js 入门指南。我们将从 Three.js 的基本概念开始&#xff0c;逐步介绍如何创建场景、添加物体、设置材质、使用光照和相机&#xff0c;以及如何实现简单的动画和交互。通过本教程&#xff0c;你将能够掌握 Three.js 的核心知识&#xf…