MyBatis—动态 SQL

MyBatis—动态 SQL

一、动态 SQL 的核心作用

动态 SQL 主要解决以下问题:

  1. 灵活性:根据不同的输入参数生成不同的 SQL 语句(如条件查询、批量操作)。

  2. 可维护性:减少重复代码,通过标签化逻辑提高 SQL 可读性。

  3. 安全性:自动处理参数绑定,防止 SQL 注入。

二、常用动态 SQL 标签

MyBatis 提供了以下标签来实现动态 SQL:

1. <if>:条件判断
  • 根据参数值是否满足条件,决定是否包含 SQL 片段。
  • 示例:
<select id="findUser" resultType="User">SELECT * FROM users<where><if test="name != null and name != ''">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></where>
</select>
  • 说明:如果 nameage 为空,则对应的条件不会被包含。
2. <choose>/<when>/<otherwise>:多条件选择
  • 类似于 Java 的 switch-case,按顺序判断条件。

  • 示例:

    <select id="findUserByCondition" resultType="User">SELECT * FROM users<where><choose><when test="name != null">AND name = #{name}</when><when test="email != null">AND email = #{email}</when><otherwise>AND status = 'active'</otherwise></choose></where>
    </select>
    
  • 说明:按顺序判断 nameemail,若都不满足则执行默认条件。

3. <where>:智能处理 WHERE 子句
  • 自动去除多余的 ANDOR,并自动添加 WHERE 关键字。

  • 示例:

    <select id="findUser" resultType="User">SELECT * FROM users<where><if test="name != null">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></where>
    </select>
    
    • 结果:若 nameage 都为空,则生成 SELECT * FROM users(无 WHERE 子句);若 name 不为空,则生成 WHERE name = ?
4. <set>:动态更新字段
  • 用于 UPDATE 语句,自动去除末尾逗号。

  • 示例:

    <update id="updateUser">UPDATE users<set><if test="name != null">name = #{name},</if><if test="email != null">email = #{email},</if></set>WHERE id = #{id}
    </update>
    
    • 结果:若 nameemail 都不为空,生成 SET name = ?, email = ?;若只有一个字段不为空,自动去除末尾逗号。
5. <foreach>:遍历集合
  • 用于批量操作(如 IN 子句、批量插入)。

  • 示例:

    <select id="findUsersByIds" resultType="User">SELECT * FROM usersWHERE id IN<foreach item="id" collection="list" open="(" separator="," close=")">#{id}</foreach>
    </select>
    
    • 结果:若传入的 list[1, 2, 3],生成 WHERE id IN (1, 2, 3)
6. <trim>:灵活拼接 SQL
  • 手动控制 SQL 片段的前缀和后缀,常用于复杂逻辑。

  • 示例:

    <trim prefix="WHERE" prefixOverrides="AND |OR "><if test="name != null">AND name = #{name}</if>
    </trim>
    
    • 说明:若 name 为空,则不生成 WHERE;若 name 不为空,生成 WHERE name = ?

三、动态 SQL 的实现原理

  1. XML 解析:MyBatis 启动时加载 Mapper XML 文件,解析动态 SQL 标签。
  2. SQL 拼接:运行时根据传入参数动态生成 SQL 片段。
  3. 参数绑定:使用 #{} 绑定参数,防止 SQL 注入。
  4. 预编译:最终生成的 SQL 被发送给数据库驱动,创建 PreparedStatement

四、动态 SQL 的应用场景

  1. 条件查询:根据用户输入动态过滤条件。
  2. 批量操作:批量插入、更新、删除。
  3. 多表关联:根据业务需求动态关联不同表。
  4. 复杂业务逻辑:如动态排序、分页等。

五、最佳实践

  1. 避免复杂嵌套:过多嵌套会降低可读性,建议拆分逻辑。
  2. 合理使用 <where><set>:简化 SQL 片段。
  3. 测试动态 SQL:通过日志查看生成的 SQL,确保逻辑正确。
  4. 参数校验:在业务层校验参数,避免无效条件。

六、示例:综合使用动态 SQL(实战)

比如我们已经写完了controller层,entity层,mapper层,service层等Impl。

动态SQL实现:修改mapper层:(注释掉SQL注解)

@Mapper
public interface UsersMapper {@Select("insert into users(account,password,uname,gender,age,phone,email,address,avatar,regtime,uflag) values(#{account},#{password},#{uname},#{gender},#{age},#{phone},#{email},#{address},#{avatar},#{regtime},#{uflag})")void addUser(Users users);@Select("select * from users where account=#{account}")Users getUserByAccount(String account);//    @Select("select * from users where uflag = #{uflag} order by regtime desc")List<Users> queryUsersByUflag(Users users);//根据id查询用户@Select("select * from users where account = #{id}")Users queryUsersById(String id);//审核通过
//    @Update("update users set uflag = #{uflag} where account = #{account}")void updateUser(Users users);//删除家长@Delete("delete from users where account = #{id}")void delUsers(String id);
}

这些SQL注解我们写进resources/mapper/UsersMapper.xml这里。

例如:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bkty.turtorsystem.mapper.UsersMapper"><!--根据动态的条件查询用户--><select id="queryUsersByUflag"  resultType="Users"parameterType="Users">select * from users<where><if test="uflag != null and uflag != ''">uflag = #{uflag}</if><if test="account != null and account != ''">and account = #{account}</if><if test="uname != null and uname != ''">and uname = #{uname}</if><if test="password != null and password != ''">and password = #{password}</if><if test="email != null and email != ''">email = #{email}</if><if test="phone != null and phone != ''">and phone like concat('%',#{phone},'%')</if><if test="gender != null and gender != ''">and gender = #{gender}</if><if test="age != null and age != ''">and age = #{age}</if><if test="address != null and address != ''">address = #{address}</if><if test="condition != null and condition != ''">${condition}</if></where>order by regtime desc</select><update id="updateUser" parameterType="Users">update users<set><if test="account != null and account != ''">account = #{account},</if><if test="password != null and password != ''">password = #{password},</if><if test="uname != null and uname != ''">uname = #{uname},</if><if test="gender != null and gender != ''">gender = #{gender},</if><if test="age != null and age != ''">age = #{age},</if><if test="phone != null and phone != ''">phone = #{phone},</if><if test="email != null and email != ''">email = #{email},</if><if test="address != null and address != ''">address = #{address},</if><if test="avatar != null and avatar != ''">avatar = #{avatar},</if><if test="regtime != null and regtime != ''">regtime = #{regtime},</if><if test="uflag != null and uflag != ''">uflag =#{uflag},</if></set>where account = #{account}</update>
</mapper>
<mapper namespace="com.bkty.turtorsystem.mapper.UsersMapper">

这个namespace=指向我的mapper,相当于注解SQL,把注解改成了xml。

1. 查询语句:queryUsersByUflag

<select id="queryUsersByUflag" resultType="Users" parameterType="Users">select * from users<where><if test="uflag != null and uflag != ''">uflag = #{uflag}</if><if test="account != null and account != ''">and account = #{account}</if><!-- 其他字段的 <if> 条件 --><if test="condition != null and condition != ''">${condition}</if></where>order by regtime desc
</select>
功能说明
  • 作用:根据传入的 Users 对象中的字段动态生成 SQL 查询条件,查询 users 表中的记录。
  • 动态条件:
    • 使用 <where> 标签包裹所有条件,MyBatis 会自动处理 ANDOR 的冗余问题(例如,如果第一个条件不成立,WHERE 关键字不会被输出)。
    • 每个 <if> 标签检查字段是否非空,若非空则添加对应的查询条件。
    • 特殊字段 condition 使用 ${condition} 直接拼接 SQL(需注意 SQL 注入风险)。
关键点
  1. 字段条件:
    • 所有字段(如 uflag, account, uname 等)都通过 <if> 动态判断是否添加到查询条件中。
    • 注意:第一个条件(uflag)没有加 AND,但 <where> 标签会自动处理这种情况,避免语法错误。
  2. condition 字段:
    • 使用 ${condition} 直接拼接原始 SQL 片段(例如 1=1status='active')。
    • 风险${} 不会进行参数绑定,存在 SQL 注入风险,需确保传入值的安全性。
  3. 排序:
    • 固定按 regtime 降序排列。
示例

假设传入的 Users 对象包含 uflag="1"account="test123",生成的 SQL 为:

SELECT * FROM users 
WHERE uflag = '1' AND account = 'test123' 
ORDER BY regtime DESC;

2. 更新语句:updateUser

<update id="updateUser" parameterType="Users">update users<set><if test="account != null and account != ''">account = #{account},</if><!-- 其他字段的 <if> 条件 --><if test="uflag != null and uflag != ''">uflag =#{uflag},</if></set>where account = #{account}
</update>
功能说明
  • 作用:根据传入的 Users 对象中的字段动态更新 users 表中的记录。
  • 动态更新字段:
    • 使用 <set> 标签包裹所有字段更新逻辑,MyBatis 会自动去除末尾多余的逗号。
    • 每个 <if> 标签判断字段是否非空,若非空则更新对应字段。
  • 更新条件:
    • 使用 account = #{account} 作为更新条件(需确保 account 是唯一标识字段)。
关键点
  1. 字段更新:
    • 所有字段(如 account, password, uname 等)都通过 <if> 动态判断是否更新。
    • 注意:每个字段条件后都有逗号 ,,但 <set> 会自动去除最后一个字段的逗号。
  2. 更新条件:
    • 使用 account = #{account} 作为更新条件,需确保 account 是唯一值(否则可能更新多条记录)。
  3. 潜在问题:
    • 如果 account 不唯一,可能会导致意外更新多条记录。
    • 更推荐使用主键(如 id)作为更新条件。
示例

假设传入的 Users 对象包含 account="test123"uname="NewName",生成的 SQL 为:

UPDATE users 
SET account = 'test123', uname = 'NewName' 
WHERE account = 'test123';

七、总结

MyBatis 的动态 SQL 通过标签化逻辑,解决了传统 SQL 硬编码的问题,使代码更简洁、安全且灵活。合理使用 <if><where><foreach> 等标签,可以大幅提升开发效率和代码质量。

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

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

相关文章

Python机器学习笔记(二十五、算法链与管道)

对于许多机器学习算法,特定数据表示非常重要。首先对数据进行缩放,然后手动合并特征,再利用无监督机器学习来学习特征。因此,大多数机器学习应用不仅需要应用单个算法,而且还需要将许多不同的处理步骤和机器学习模型链接在一起。Pipeline类可以用来简化构建变换和模型链的…

YOLOv3深度解析:多尺度特征融合与实时检测的里程碑

一、YOLOv3的诞生&#xff1a;继承与突破的起点 YOLOv3作为YOLO系列的第三代算法&#xff0c;于2018年由Joseph Redmon等人提出。它在YOLOv2的基础上&#xff0c;针对小目标检测精度低、多类别标签预测受限等问题进行了系统性改进。通过引入多尺度特征图检测、残差网络架构和独…

已解决(亲测有效!):安装部署Docker Deskpot之后启动出现Docker Engine Stopped!

文章目录 已解决&#xff1a;安装部署Docker Deskpot之后启动出现Docker Engine Stopped&#xff01;个人环境介绍自己的解决问题思路&#xff08;详细过程附截图&#xff09;1.打开控制面板2.点击程序和功能3.点击启动或关闭windows功能4.Hyper-V5.右键菜单栏的windows图标点击…

PCIE接收端检测机制分析

PCIE接收端检测机制分析 1、PCIE的接收端检测机制 接收器检测电路作为发射器的一部分实现&#xff0c;必须正确检测是否存在与ZRX-DC参数&#xff08;40Ω-60Ω&#xff09;隐含的直流阻抗等效的负载阻抗。 接收器检测序列的推荐行为如下&#xff1a; ‌初始状态‌&#xff…

[模型部署] 3. 性能优化

&#x1f44b; 你好&#xff01;这里有实用干货与深度分享✨✨ 若有帮助&#xff0c;欢迎&#xff1a;​ &#x1f44d; 点赞 | ⭐ 收藏 | &#x1f4ac; 评论 | ➕ 关注 &#xff0c;解锁更多精彩&#xff01;​ &#x1f4c1; 收藏专栏即可第一时间获取最新推送&#x1f514;…

InternVL3: 利用AI处理文本、图像、视频、OCR和数据分析

InternVL3推动了视觉-语言理解、推理和感知的边界。 在其前身InternVL 2.5的基础上,这个新版本引入了工具使用、GUI代理操作、3D视觉和工业图像分析方面的突破性能力。 让我们来分析一下是什么让InternVL3成为游戏规则的改变者 — 以及今天你如何开始尝试使用它。 InternVL…

鸿蒙 ArkUI - ArkTS 组件 官方 UI组件 合集

ArkUI 组件速查表 鸿蒙应用开发页面上需要实现的 UI 功能组件如果在这 100 多个组件里都找不到&#xff0c;那就需要组合造轮子了 使用技巧&#xff1a;先判断需要实现的组件大方向&#xff0c;比如“选择”、“文本”、“信息”等&#xff0c;或者是某种形状比如“块”、“图…

HTTP GET报文解读

考虑当浏览器发送一个HTTP GET报文时&#xff0c;通过Wireshark 俘获到下列ASCII字符串&#xff1a; GET /cs453/index.html HTTP/1.1 Host: gaia.cs.umass.edu User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.2) Gecko/20040804 Netscape/7.2 (ax) Acc…

【Linux网络】数据链路层

数据链路层 用于两个设备&#xff08;同一种数据链路节点&#xff09;之间进行传递。 认识以太网 “以太网” 不是一种具体的网络&#xff0c;而是一种技术标准&#xff1b;既包含了数据链路层的内容&#xff0c;也包含了一些物理层的内容。例如&#xff1a;规定了网络拓扑结…

【打破信息差】萌新认识与入门算法竞赛

阅前须知 XCPC萌新互助进步群2️⃣&#xff1a;174495261 博客主页&#xff1a;resot (关注resot谢谢喵) 针对具体问题&#xff0c;应当进行具体分析&#xff1b;并无放之四海而皆准的方法可适用于所有人。本人尊重并支持每位学习者对最佳学习路径的自主选择。本篇所列训练方…

logrotate按文件大小进行日志切割

✅ 编写logrotate文件&#xff0c;进行自定义切割方式 adminip-127-0-0-1:/data/test$ cat /etc/logrotate.d/test /data/test/test.log {size 1024M #文件达到1G就切割rotate 100 #保留100个文件compressdelaycompressmissingoknotifemptycopytruncate #这个情况服务不用…

2025认证杯二阶段C题完整论文讲解+多模型对比

基于延迟估计与多模型预测的化工生产过程不合格事件预警方法研究 摘要 化工生产过程中&#xff0c;污染物浓度如SO₂和H₂S对生产过程的控制至关重要。本文旨在通过数据分析与模型预测&#xff0c;提出一种基于延迟估计与特征提取的多模型预测方法&#xff0c;优化阈值设置&a…

前端精度问题全解析:用“挖掘机”快速“填平精度坑”的完美解决方案

写在前面 “为什么我的计算在 React Native 中总是出现奇怪的精度问题?” —— 这可能是许多开发者在作前端程序猿的朋友们都会遇到的第一个头疼问题。本文将深入探讨前端精度问题的根源,我将以RN为例,并提供一系列实用解决方案,让你的应用告别计算误差。 一、精度问题的…

2024 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛) 解题报告 | 珂学家

前言 题解 2024 睿抗机器人开发者大赛CAIP-编程技能赛-本科组(国赛)。 国赛比省赛难一些&#xff0c;做得汗流浃背&#xff0c;T_T. RC-u1 大家一起查作弊 分值: 15分 这题真的太有意思&#xff0c;看看描述 在今年的睿抗比赛上&#xff0c;有同学的提交代码如下&#xff1…

hghac和hgproxy版本升级相关操作和注意事项

文章目录 环境文档用途详细信息 环境 系统平台&#xff1a;N/A 版本&#xff1a;4.5.6,4.5.7,4.5.8 文档用途 本文档用于高可用集群环境中hghac组件和hgproxy组件替换和升级操作 详细信息 1.关闭服务 所有数据节点都执行 1、关闭hgproxy服务 [roothgdb01 tools]# system…

userfaultfd内核线程D状态问题排查

问题现象 运维反应机器上出现了很多D状态进程&#xff0c;也kill不掉,然后将现场保留下来进行排查。 排查过程 都是内核线程&#xff0c;先看下内核栈D在哪了&#xff0c;发现D在了userfaultfd的pagefault流程。 uffd知识补充 uffd探究 uffd在firecracker与e2b的架构下使…

深入解析:构建高性能异步HTTP客户端的工程实践

一、架构设计原理与核心优势 HTTP/2多路复用技术的本质是通过单一的TCP连接并行处理多个请求/响应流&#xff0c;突破了HTTP/1.1的队头阻塞限制。在异步编程模型下&#xff0c;这种特性与事件循环机制完美结合&#xff0c;形成了高性能网络通信的黄金组合。相较于传统同步客户…

根据台账批量制作个人表

1. 前期材料准备 1&#xff09;要有 人员总的信息台账 2&#xff09;要有 个人明白卡模板 2. 开始操作 1&#xff09;打开 人员总的信息台账&#xff0c;选择所需要的数据模块&#xff1b; 2&#xff09;点击插入&#xff0c;选择数据透视表&#xff0c;按流程操作&…

《AI大模型应知应会100篇》第65篇:基于大模型的文档问答系统实现

第65篇&#xff1a;基于大模型的文档问答系统实现 &#x1f4da; 摘要&#xff1a;本文详解如何构建一个基于大语言模型&#xff08;LLM&#xff09;的文档问答系统&#xff0c;支持用户上传 PDF 或 Word 文档&#xff0c;并根据其内容进行智能问答。从文档解析、向量化、存储到…

RTK哪个品牌好?2025年RTK主流品牌深度解析

在测绘领域&#xff0c;RTK 技术的发展日新月异&#xff0c;选择一款性能卓越、稳定可靠的 RTK 设备至关重要。2025 年&#xff0c;市场上涌现出众多优秀品牌&#xff0c;本文将深入解析几大主流品牌的核心竞争力。 华测导航&#xff08;CHCNAV&#xff09;&#xff1a;技术创…