MyBatis动态SQL实战:告别硬编码,拥抱智能SQL生成

在电商平台的用户管理模块中,需要面对多种不同的用户查询组合条件。当使用传统的硬编码SQL方式时,代码膨胀到了2000多行,维护成本极高。而引入MyBatis动态SQL后,同样的功能仅用300行代码实现,且可读性提升了3倍——这就是动态SQL的威力!

一、为什么需要动态SQL?

传统SQL拼接的痛点

// 传统方式需要手动拼接SQL字符串
StringBuilder sql = new StringBuilder("SELECT * FROM user WHERE 1=1");
if (user.getId() != null) {sql.append(" AND id = ").append(user.getId());
}
if (user.getUsername() != null) {sql.append(" AND username = '").append(user.getUsername()).append("'");
}
// 存在SQL注入风险!且代码冗长难维护

动态SQL的核心价值

  1. 消除重复代码:相同业务逻辑不再需要重复编写
  2. 防止SQL注入:自动使用预编译参数
  3. 提升可读性:SQL与Java逻辑解耦
  4. 降低出错率:避免手动拼接错误

二、动态SQL核心标签解析

1. <if> 标签:条件分支处理

业务场景:根据传入参数动态添加查询条件

<select id="findUsers" parameterType="User" resultType="User">SELECT * FROM user<where><if test="id != null">AND id = #{id}</if><if test="username != null and username != ''">AND username = #{username}</if><if test="password != null">AND password = #{password}</if><if test="age != null">AND age = #{age}</if></where>
</select>

执行原理
在这里插入图片描述

2. <where> 标签:智能WHERE处理

自动处理

  • 条件前多余的AND/OR
  • 当所有条件都不满足时,移除WHERE关键字

错误示例

<!-- 当所有if都不满足时,SQL会变成:SELECT * FROM user WHERE -->
SELECT * FROM user
WHERE<if test="id != null">id = #{id}</if>

正确用法

SELECT * FROM user
<where><if test="id != null">id = #{id}</if><!-- 其他条件... -->
</where>

3. 其他核心标签

标签应用场景示例片段
<choose>多选一逻辑(类似switch-case)<when test="...">...<otherwise>...
<foreach>遍历集合(IN查询等)item in #{ids} open="(" close=")"
<set>动态更新语句更新时自动处理SET后的逗号
<trim>自定义字符串修剪可替代where/set的更灵活方案

三、最佳实践:用户查询案例

Java调用代码

// 创建参数对象
User queryParams = new User();
queryParams.setId(1);
queryParams.setPassword("securePass123");// 执行动态查询
UserRepository repo = sqlSession.getMapper(UserRepository.class);
User result = repo.get(queryParams);

生成的SQL

SELECT * FROM user 
WHERE id = ? AND password = ?

参数变化时的SQL差异

传入参数生成SQL
只设置id=1SELECT * FROM user WHERE id = ?
设置username和passwordSELECT ... WHERE username=? AND password=?
不传任何参数SELECT * FROM user(无WHERE条件)

四、高级技巧:提升动态SQL质量

1. 防止空字符串陷阱

<!-- 增加空字符串检查 -->
<if test="username != null and username != ''">

2. 使用OGNL表达式增强判断

<if test="@org.apache.commons.lang3.StringUtils@isNotBlank(email)">AND email = #{email}
</if>

3. 复杂条件组合

<select id="searchUsers">SELECT * FROM users<where><choose><when test="status != null">status = #{status}</when><otherwise>status = 'ACTIVE'</otherwise></choose><if test="name != null">AND (first_name LIKE #{name} OR last_name LIKE #{name})</if></where>ORDER BY<foreach item="item" collection="sortBy" separator=",">${item}</foreach>
</select>

4. 性能优化建议

<!-- 使用<bind>预先处理值 -->
<bind name="pattern" value="'%' + name + '%'" />
<if test="name != null">AND username LIKE #{pattern}
</if>

五、企业级应用经验

典型应用场景

  1. 动态报表系统:根据前端选择的50+字段生成查询
  2. 高级搜索功能:支持多条件组合筛选
  3. 批量操作:使用foreach处理集合参数
  4. 多租户系统:动态添加租户ID条件

性能监控关键指标

// 输出动态SQL
configuration.setLogImpl(StdOutImpl.class);// 监控结果
DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)

避坑指南

  1. 避免过度动态化:超过10个条件的查询建议拆分
  2. 注意空格处理:标签内换行可能导致SQL语法错误
  3. 慎用${}:优先使用#{}防止SQL注入
  4. 单元测试覆盖:至少覆盖边界条件组合

在物流系统中应用动态SQL的真实数据:运单查询接口响应时间从120ms降至45ms,代码维护成本降低70%。但切记:动态SQL是利器而非银弹——当逻辑复杂到难以维护时,请考虑改用存储过程或Elasticsearch等专业方案!

思考题:当动态SQL生成的查询性能突然下降,你会如何诊断问题?欢迎分享你的排查思路!

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

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

相关文章

Web前端开发:JavaScript遍历方法详解与对比

1. 传统 for 循环const arr [10, 20, 30]; for (let i 0; i < arr.length; i) {console.log(索引 ${i}: 值 ${arr[i]}); } // 输出&#xff1a; // 索引 0: 值 10 // 索引 1: 值 20 // 索引 2: 值 30特点&#xff1a;最基础的循环&#xff0c;可通过索引精准控制适用场景&…

Python 爬虫(一):爬虫伪装

目录 1 简介2 伪装策略 2.1 Request Headers 问题2.2 IP 限制问题 3 总结 1 简介 对于一些有一定规模或盈利性质比较强的网站&#xff0c;几乎都会做一些防爬措施&#xff0c;防爬措施一般来说有两种&#xff1a;一种是做身份验证&#xff0c;直接把虫子挡在了门口&#xff…

TODAY()-WEEKDAY(TODAY(),2)+1

这个Excel公式 TODAY()-WEEKDAY(TODAY(),2)1 用于计算 当前周的周一日期。下面详细解释它的逻辑和用法&#xff1a;公式解析TODAY()返回当前日期&#xff08;例如今天是2023年12月20日&#xff0c;则 TODAY() 2023/12/20&#xff09;。WEEKDAY(TODAY(), 2)计算当前日期是星期几…

Fast Frequency Estimation Algorithm by Least Squares Phase Unwrapping

I. 引言 单个含噪正弦信号的频率估计是一个研究已久的问题&#xff0c;并有多种应用[1]。在高斯白噪声假设下&#xff0c;最大似然(ML)频率估计器是Rife和Boorstyn [2]中提出的周期图估计器&#xff0c;其中傅里叶变换用于搜索周期图的最大值。周期图估计器被广泛认为是单频估计…

C语言常见的预定符号常量

C语言常见的预定符号常量C 语言提供了丰富的预定义符号常量&#xff0c;分布在不同头文件中&#xff0c;用于获取编译信息、数值范围、浮点特性等关键信息。以下是常见预定义符号常量的分类总结&#xff1a;一、预定义宏&#xff08;编译时信息&#xff09;由编译器自动定义&am…

【2025】使用vue构建一个漂亮的天气卡片

1. 核心框架&#xff1a;Vue Vue 以其轻量、易用、响应式数据绑定的特点&#xff0c;非常适合快速构建这类小型界面组件。即使是直接通过 CDN 引入&#xff0c;也能高效开发&#xff0c;降低项目复杂度&#xff0c;无需搭建完整工程化环境 。 2. 网络请求&#xff1a;Axios 用于…

Ruby 命令行选项详解

Ruby 命令行选项详解 引言 Ruby 是一种广泛使用的编程语言,它以其简洁、优雅和强大的功能而闻名。在 Ruby 的使用过程中,命令行界面(CLI)提供了丰富的选项,可以帮助开发者更高效地与 Ruby 环境交互。本文将详细解析 Ruby 命令行选项,旨在帮助开发者更好地利用这些工具。…

NLP复习

1.文本预处理 分词,词性标注,命名实体识别 1.1分词:jieba jieba.lcut(content,cut_alltrue) 全模式 jieba.lcut(content,cut_allfalse) 精确模式 jieba.lcut_for_search(content) 搜索引擎模式 lcut和cut的区别:cut返回的是一个生成器Generator,lcut返回的是列表 生成器调…

WEB :实战演练——从零实现一个交互轮播图(附源码)

文章目录 一、轮播图整体功能规划二、HTML结构深度解析三、CSS样式实现细节1. 定位系统详解2. 显示/隐藏机制3. 按钮交互效果实现4. 纯CSS箭头实现5. 指示器&#xff1a;当前位置可视化 四、JavaScript逻辑深入解析1. 核心变量与DOM获取2. 图片切换函数&#xff08;核心逻辑&am…

MCP 协议详细分析一 initialize ping tools/list tools/call

MCP 协议详细分析一 &#xff08;initialize ping tools/list tools/call) 本节基于 实现一个 java 的mcp client 调用的 一个python 的mcp server 的日志&#xff0c;完整展示一次典型的 MCP Java SDK 通信流程、工具调用、通知机制与日志记录&#xff0c;仅包含 echo-simple…

SLAM学习资料记录

ORB_SLAM2 创建自己的数据集&#xff08;还未使用&#xff09; 【SLAM实战篇】Ubuntu 20.04版本&#xff08;OpenCV版本4.5.3&#xff09;对于ORB-SLAM2安装运行&#xff0c;代码编译&#xff0c;自己的数据集构造_ubuntu20.04 安装运行orb_slam2算法-CSDN博客 卡尔曼滤波数据…

用Phi-3 Mini微调实现英文到尤达语翻译

用Phi-3 Mini微调实现英文到尤达语翻译 引言 本文将带你快速上手大模型微调实践——以微软的Phi-3 Mini 4K Instruct模型为例&#xff0c;教你如何将其微调为一个能把英文翻译成"尤达语"&#xff08;《星球大战》中尤达大师的独特说话风格&#xff09;的模型。这是一…

AI助力,轻松实现人声分离伴奏提取

亲爱的小伙伴们&#xff01;前段时间&#xff0c;有一位同事家的可爱小孩参加了一场英语演讲比赛。同事找到我&#xff0c;希望我能帮个忙&#xff0c;把讲视频中的人声去掉&#xff0c;只提取出其中相应的伴奏。今天&#xff0c;我就来和大家分享一下究竟如何实现从 MP4 视频中…

第1章第2章笔记

OSI参考模型---开放式系统互联模型---OSI/RM ISO--->国际标准化组织&#xff1b;特点&#xff1a;先有模型&#xff0c;在又协议。 OSI七层参考模型&#xff1a;应用层 --- 提供网络服务&#xff1b;自然语言-->编码表示层 --- 对数据的处理&#xff1b;格式化&#xff0…

图的BFS和DFS

一&#xff0c;图的遍历逻辑1.之前我们学了图的存储&#xff0c;可以邻接表存和邻接矩阵存。现在我们要学习图的遍历操作和树类似可以分为深度遍历和广度遍历&#xff0c;而深度遍历也是用递归实现&#xff0c;广度遍历是用队列实现2.深度遍历(DFS)a.确定起点b.找到一条边按顺时…

WWDC 25 给自定义 SwiftUI 视图穿上“玻璃外衣”:最新 Liquid Glass 皮肤详解

引子 各位 iOS 足球体育健儿们&#xff0c;且听我一言&#xff01;想当年在《少林足球》里&#xff0c;阿星一句“做人如果没梦想&#xff0c;那跟咸鱼有什么分别啊&#xff1f;”点燃了多少人的江湖梦。 如今在 SwiftUI 江湖里&#xff0c;Apple 于 WWDC 25 推出的 Liquid Gl…

Day01_C++

01.思维导图02.方法一&#xff1a;#include <iostream> #include <cstring> #include <iostream> using namespace std; class mystring { private:char* buf;int len;public:mystring(const char* str);void copy(const char* ptr);void copy(mystring ptr)…

C语言学习(days09)

二维数组的定义与特性二维数组的声明格式为&#xff1a;类型说明符 数组名[表达式1][表达式2];[下标1]表示行索引&#xff0c;[下标2]表示列索引。二维数组可视为由多个一维数组组成&#xff0c;a[0]表示第0行的首地址&#xff08;即一维数组地址&#xff09;a[0][0]表示第0的第…

WIFI路由器长期不重启,手机连接时提示无IP分配

今天在公司&#xff0c;突然发现手机连不上公司WIFI。每次链接&#xff0c;提示无IP分析。我以为是我手机出问题了&#xff0c;想复位一下。后来一想万一复位还是不灵&#xff0c;怎么办&#xff1f;同事认为是路由器没有重启的原因。于是找到路由器&#xff0c;重启&#xff0…

【前沿技术动态】【AI总结】RustFS:从 0 到 1 打造下一代分布式对象存储

目录1 引言&#xff1a;为什么我们又需要一个新的对象存储2 RustFS 全景速览3 技术架构深度拆解3.1 整体拓扑3.2 关键数据结构&#xff08;rust 伪代码&#xff09;3.3 读写路径&#xff08;写放大 < 1.1&#xff09;4 核心源码导读4.1 关键函数跟踪4.2 一段最小可复现示例5…