当前位置: 首页 > news >正文

MyBatis Plus Wrapper 详细分析与原理

MyBatis Plus 是一个 MyBatis 的增强工具,其核心特性之一是提供了强大的 Wrapper 机制,用于动态构建 SQL 查询条件、排序、更新等操作。Wrapper 基于链式调用设计,简化了复杂 SQL 的编写。下面我将从组装条件、排序条件、删除条件等角度,逐一进行详细分析,并结合代码示例和原理介绍。所有解释基于 MyBatis Plus 3.x 版本,确保真实可靠。

1. 组装条件
  • 作用:用于构建 WHERE 子句中的查询条件,如等于、不等于、大于等。
  • 方法:常用方法包括 eq()(等于)、ne()(不等于)、gt()(大于)、lt()(小于)、like()(模糊查询)等。这些方法支持链式调用。
  • 原理:Wrapper 内部维护一个条件列表(List<Segment>),每次调用条件方法时,添加对应的 SQL 片段。最终,MyBatis Plus 通过 SqlHelper 解析这些片段,生成完整的 SQL。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name", "John")  // 生成 name = 'John'.gt("age", 18);     // 生成 AND age > 18
    // 生成的 SQL: SELECT * FROM user WHERE name = 'John' AND age > 18
    

2. 组装排序条件
  • 作用:添加 ORDER BY 子句,指定查询结果的排序方式。
  • 方法:使用 orderByAsc()(升序)和 orderByDesc()(降序),可指定多个字段。
  • 原理:排序条件被存储为独立的片段,在生成 SQL 时追加到 WHERE 子句之后。优先级由调用顺序决定。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("status", 1).orderByAsc("age")     // 按 age 升序.orderByDesc("name");  // 再按 name 降序
    // 生成的 SQL: SELECT * FROM user WHERE status = 1 ORDER BY age ASC, name DESC
    

3. 组装删除条件
  • 作用:用于构建删除操作的 WHERE 条件,类似于查询条件。
  • 方法:与组装条件相同,使用 eq()gt() 等方法,但应用于 delete() 方法。
  • 原理:删除操作时,Mapper 的 delete 方法接受 Wrapper 参数,MyBatis Plus 将条件转换为 DELETE 语句的 WHERE 部分。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.lt("age", 18);  // 年龄小于 18
    userMapper.delete(wrapper);  // 执行删除
    // 生成的 SQL: DELETE FROM user WHERE age < 18
    

4. QueryWrapper 修改
  • 作用:QueryWrapper 对象支持动态修改条件,通过链式调用添加、覆盖或组合条件。
  • 方法:所有条件方法都返回当前对象,支持连续调用。例如,eq().or().gt() 可修改现有条件。
  • 原理:QueryWrapper 是可变的(mutable),内部状态随方法调用更新。修改时,新条件追加到列表,旧条件不会被清除,除非显式重置。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name", "John");  // 初始条件
    wrapper.or().gt("age", 30);  // 修改为 OR 条件
    // 生成的 SQL: SELECT * FROM user WHERE name = 'John' OR age > 30
    

5. 条件优先级
  • 作用:控制多个条件的逻辑优先级,避免 SQL 歧义,如 AND 和 OR 的嵌套。
  • 方法:使用 and()or() 方法结合 Lambda 表达式或嵌套 Wrapper 来显式分组。默认优先级为从左到右,但推荐使用括号控制。
  • 原理:MyBatis Plus 通过 and()or() 方法添加逻辑操作符,内部使用栈结构管理括号。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("status", 1).and(i -> i.eq("name", "John").or().eq("name", "Alice"))  // 括号分组.lt("age", 30);
    // 生成的 SQL: SELECT * FROM user WHERE status = 1 AND (name = 'John' OR name = 'Alice') AND age < 30
    

6. 组装 select 子句
  • 作用:指定查询的字段列表,避免 SELECT *,提升性能。
  • 方法:使用 select() 方法,传入字段名数组或字符串。
  • 原理select() 方法设置一个字段列表,在生成 SQL 时替换默认的 *。MyBatis Plus 会验证字段是否存在(基于实体类映射)。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.select("id", "name", "age")  // 只查询 id, name, age.eq("status", 1);
    // 生成的 SQL: SELECT id, name, age FROM user WHERE status = 1
    

7. 组装子查询
  • 作用:在条件中嵌入子查询,如 IN 或 EXISTS 子句。
  • 方法:使用 inSql()notInSql()exists()notExists() 等方法,传入子查询 SQL 字符串。
  • 原理:子查询作为字符串参数被直接嵌入到条件片段中。MyBatis Plus 不解析子查询内容,仅拼接 SQL,需确保子查询语法正确。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.inSql("id", "SELECT user_id FROM order WHERE amount > 100")  // 子查询.eq("active", true);
    // 生成的 SQL: SELECT * FROM user WHERE id IN (SELECT user_id FROM order WHERE amount > 100) AND active = true
    

8. condition 组装条件
  • 作用:动态添加条件,根据布尔值决定是否生效,用于运行时条件分支。
  • 方法:条件方法(如 eq())提供重载版本,第一个参数为 boolean condition。如果 condition 为 true,则添加条件;否则忽略。
  • 原理:内部检查 condition 参数,仅当 true 时添加片段。这简化了 if-else 逻辑,避免代码冗余。
  • 示例代码
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    boolean isAdult = age > 18;
    wrapper.eq(isAdult, "status", "active")  // 仅当 isAdult 为 true 时添加.ne("name", "admin");
    // 如果 isAdult=true, SQL: SELECT * FROM user WHERE status = 'active' AND name != 'admin'
    // 如果 isAdult=false, SQL: SELECT * FROM user WHERE name != 'admin'
    

9. LambdaQueryWrapper
  • 作用:使用 Lambda 表达式引用实体字段,避免硬编码字段名,提升类型安全和可读性。
  • 方法:通过 LambdaQueryWrapper<T> 类,使用如 eq(User::getName, "John") 的语法。
  • 原理:基于 Java 的 Method Reference,MyBatis Plus 通过反射获取字段名(如 User::getName 对应数据库列 name)。底层与 QueryWrapper 共享解析逻辑,但编译时检查字段存在性。
  • 示例代码
    LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
    lambdaWrapper.eq(User::getName, "John")   // 引用实体方法.gt(User::getAge, 18);
    // 生成的 SQL: SELECT * FROM user WHERE name = 'John' AND age > 18
    

10. LambdaUpdateWrapper
- **作用**:专用于更新操作,支持设置新值和条件,比 QueryWrapper 更高效。
- **方法**:继承自 `UpdateWrapper`,提供 `set()` 方法设置字段值,结合 `eq()` 等条件方法。同样支持 Lambda 表达式。
- **原理**:与 LambdaQueryWrapper 类似,但额外处理 SET 子句。更新时,MyBatis Plus 直接生成 UPDATE 语句,避免先查询后更新。
- **示例代码**:LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();updateWrapper.eq(User::getId, 1).set(User::getName, "NewName")  // 设置新值.set(User::getAge, 30);userMapper.update(null, updateWrapper);  // 执行更新// 生成的 SQL: UPDATE user SET name = 'NewName', age = 30 WHERE id = 1
整体原理介绍

MyBatis Plus 的 Wrapper 机制基于动态 SQL 生成原理:

  • 核心类AbstractWrapper 是基类,QueryWrapperLambdaQueryWrapper 等继承它。内部使用 SqlSegment 对象存储 SQL 片段(如条件、排序)。
  • SQL 生成流程
    1. 用户通过链式调用构建 Wrapper。
    2. MyBatis Plus 解析 Wrapper 时,遍历片段列表,拼接成完整 SQL 字符串。
    3. 对于 Lambda 版本,利用 SerializedLambda 提取方法引用对应的字段名。
    4. 最终,通过 MyBatis 的 SqlSession 执行 SQL。
  • 优势
    • 类型安全:Lambda Wrapper 减少字段名错误。
    • 动态性:支持运行时条件修改。
    • 性能:避免手动拼接 SQL,减少注入风险。
  • 数学逻辑应用:在条件优先级中,Wrapper 使用逻辑运算符(确保 SQL 正确性,嵌套条件生成的结构),通过括号保证运算顺序。

通过上述分析,MyBatis Plus Wrapper 提供了一种高效、灵活的方式来构建复杂查询,适用于各种 CRUD 操作。实际使用时,推荐结合 Lambda 版本以提升代码健壮性。

http://www.dtcms.com/a/305487.html

相关文章:

  • 设计模式十四:适配器模式(Adapter Pattern)
  • MCP提示词工程:上下文注入的艺术与科学
  • 【计算机视觉与代码大模型全景解析:从理论基础到学习路线】
  • VSCode高效集成开发全流程优化
  • [论文阅读] 人工智能 + 软件工程 | 增强RESTful API测试:针对MongoDB的搜索式模糊测试新方法
  • Jaeger理论、实战、问题记录
  • Python 中使用 OpenCV 库来捕获摄像头视频流并在窗口中显示
  • RAG实战指南 Day 28:RAG系统缓存与性能优化
  • Web3:赛道划分与发展趋势解析
  • JDBC编程笔记
  • 创建型设计模式-Builder
  • Git链接备用手册
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博内容IP地图可视化分析实现
  • 《设计模式之禅》笔记摘录 - 11.策略模式
  • 15 - 多模态大语言模型 — 图文 “牵线” 系统 “成长记”:借 CLIP 练本领,从图像与文字里精准 “搭鹊桥” 的全过程 (呆瓜版 - 2 号)
  • Java源码构建智能名片小程序
  • 短剧小程序系统开发:重塑影视内容消费格局
  • 北京理工大学医工交叉教学实践分享(1)|如何以实践破解数据挖掘教学痛点
  • 招工招聘小程序系统开发——打造一站式招聘服务平台
  • DISTILLM:迈向大型语言模型的简化蒸馏方法
  • 基于动态权重-二维云模型的川藏铁路桥梁施工风险评估MATLAB代码
  • [硬件电路-106]:模拟电路 - 电路为什么会出现不同的频率特性?元件频率依赖性、信号传输路径、电路拓扑结构、外部因素
  • 新手向:DeepSeek 部署中的常见问题及解决方案
  • C语言:函数指针、二级指针、常量指针常量、野指针
  • 域名https证书
  • 【动态规划算法】斐波那契数列模型
  • 深入理解PostgreSQL的MVCC机制
  • webpack-性能优化
  • 告别内存泄漏:你的Rust语言30天征服计划
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | 3dBackgroundBoxes(3D背景盒子组件)