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

MybatisPlus 一些技巧

查询简化

SimpleQuery

有工具类 com.baomidou.mybatisplus.extension.toolkit.SimpleQueryselectList 查询后的结果进行了封装,使其可以通过 Stream 流的方式进行处理,从而简化了 API 的调用。

方法 list()

支持对一个列表提取某个字段,并同时执行任意多个 Consumer。可以省去 for 循环或 stream().forEach()。

// 假设有一个 User 实体类和对应的 BaseMapper
List<Long> ids = SimpleQuery.list(Wrappers.lambdaQuery(User.class), // 使用 lambda 查询构建器User::getId, // 提取的字段,这里是 User 的 idSystem.out::println, // 第一个 peek 操作,打印每个用户user -> userNames.add(user.getName()) // 第二个 peek 操作,将每个用户的名字添加到 userNames 列表中
);

方法 keyMap()

可以得到一个 key 是指定字段的值,value 是对应实体的 Map,方便用于需要根据某个字段查找对应实体的情况。参数也包含任意个 Consumer。

// 假设有一个 User 实体类和对应的 BaseMapper
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getStatus, "active"); // 查询状态为 "active" 的用户// 使用 keyMap 方法查询并封装结果
Map<String, User> userMap = SimpleQuery.keyMap(queryWrapper, // 查询条件构造器User::getUsername, // 使用用户名作为键user -> System.out.println("Processing user: " + user.getUsername()) // 打印处理的用户名
);// 遍历结果
for (Map.Entry<String, User> entry : userMap.entrySet()) {System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

方法 map()

可以得到一个 key 是指定字段的值,value 也是指定字段的值 Map。可以用于如字典的这种情况。

// 假设有一个 User 实体类和对应的 BaseMapper
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getStatus, "active"); // 查询状态为 "active" 的用户// 使用 map 方法查询并封装结果
Map<String, Integer> userMap = SimpleQuery.map(queryWrapper, // 查询条件构造器User::getUsername, // 使用用户名作为键User::getAge, // 使用年龄作为值user -> System.out.println("Processing user: " + user.getUsername()) // 打印处理的用户名
);// 遍历结果
for (Map.Entry<String, Integer> entry : userMap.entrySet()) {System.out.println("Username: " + entry.getKey() + ", Age: " + entry.getValue());
}

方法 group()

可以对查询结果按照实体的某个熟悉进行分类,得到一个 Map<K, List>。也支持进行任意额外的副操作。并且对分组后的集合也支持下游收集器 Collector 进行进一步处理。

// 假设有一个 User 实体类和对应的 BaseMapper
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getStatus, "active"); // 查询状态为 "active" 的用户// 使用 group 方法查询并封装结果,按照用户名分组
Map<String, List<User>> userGroup = SimpleQuery.group(queryWrapper, // 查询条件构造器User::getUsername, // 使用用户名作为分组键user -> System.out.println("Processing user: " + user.getUsername()) // 打印处理的用户名
);// 遍历结果
for (Map.Entry<String, List<User>> entry : userGroup.entrySet()) {System.out.println("Username: " + entry.getKey());for (User user : entry.getValue()) {System.out.println(" - User: " + user);}
}

查询条件 QueryWrapper

inSql

用于设置单个字段的 IN 条件,但与 in 方法不同的是,inSql 允许你直接使用 String 来传递要查询的范围。

in 的方式:

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.in(User::getAge, Arrays.asList(1, 2, 3));-- 生成的 SQL
SELECT * FROM user WHERE age IN (1, 2, 3)

inSql 的方式:

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.inSql(User::getAge, "1,2,3,4,5,6");-- 生成的 SQL
SELECT * FROM user WHERE age IN (1, 2, 3, 4, 5, 6)

从二者的方法签名也能看出来效果,in 接收的是 Collect 或 Object… 而 inSql 接收的是 String。

eqSql

适用于某一字段需要对比子查询的结果的情况。 Since 3.5.6 版本

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eqSql(User::getId, "select MAX(id) from table");-- 生成的 SQL
SELECT * FROM user WHERE id = (select MAX(id) from table)

还有类似的 gtSql、geSql、ltSql、leSql,Since 3.4.3.2 版本。

但是要注意 SQL 注入问题,因为这里是直接插入到 SQL 语句中使用。

having

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.groupBy(User::getAge).having("sum(age) > {0}", 10);-- 生成的 SQL
SELECT * FROM user GROUP BY age HAVING sum(age) > 10

apply

直接拼接 SQL 片段到查询条件中。

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.apply("date_format(dateColumn, '%Y-%m-%d') = {0}", "2008-08-08");-- 使用参数占位符生成的 SQL
SELECT * FROM user WHERE date_format(dateColumn, '%Y-%m-%d') = '2008-08-08'

推荐使用占位符的写法,防止 SQL 注入。

last

允许你直接在查询的最后添加一个 SQL 片段,而不受 MyBatis-Plus 的查询优化规则影响。这个方法应该谨慎使用,因为它可能会绕过 MyBatis-Plus 的查询优化。

LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.last("limit 1");-- 生成的 SQL
SELECT * FROM user LIMIT 1

last 方法只能调用一次,多次调用将以最后一次为准。

自定义 SQL

允许在自定义的 SQL 中使用 Wrapper 的查询条件。 Since 3.0.7 版本。

参数命名:在自定义 SQL 时,传递 Wrapper 对象作为参数时,参数名必须为 ew,或者使用注解 @Param(Constants.WRAPPER) 明确指定参数为 Wrapper 对象。

使用 ${ew.customSqlSegment}:在 SQL 语句中,使用 ${ew.customSqlSegment} 来引用 Wrapper 对象生成的 SQL 片段。

// Mapper 层编写自定义 SQL 语句
public interface UserMapper extends BaseMapper<User> {@Select("SELECT * FROM user ${ew.customSqlSegment}")List<User> selectByCustomSql(@Param(Constants.WRAPPER) Wrapper<User> wrapper);
}// Service 层调用
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "张三");List<User> userList = userMapper.selectByCustomSql(queryWrapper);

也支持使用 XML 的方式调用查询条件

<select id="getAll" resultType="MysqlData">SELECT * FROM mysql_data ${ew.customSqlSegment}
</select>

其他

@EnumValue

当实体类中的某个字段是枚举类型时,使用@EnumValue注解可以告诉MyBatis-Plus在数据库中存储枚举值的哪个属性。

@TableName("sys_user")
public class User {@TableIdprivate Long id;@TableField("nickname") // 映射到数据库字段 "nickname"private String name;private Integer age;private String email;private Gender gender; // 假设 Gender 是一个枚举类型
}public enum Gender {MALE("M", "男"),FEMALE("F", "女");private String code;private String description;Gender(String code, String description) {this.code = code;this.description = description;}@EnumValue // 指定存储到数据库的枚举值为 codepublic String getCode() {return code;}
}

@TableLogic

该注解用于标记实体类中的字段作为逻辑删除字段。开发者无需手动编写逻辑删除的代码,MyBatis-Plus 会自动处理这一过程。

当执行查询操作时,MyBatis-Plus 会自动过滤掉标记为逻辑删除的记录,只返回未删除的记录。在执行更新操作时,如果更新操作会导致逻辑删除字段的值变为逻辑删除值,MyBatis-Plus 会自动将该记录标记为已删除。在执行删除操作时,MyBatis-Plus 会自动将逻辑删除字段的值更新为逻辑删除值,而不是物理删除记录。

@TableName("sys_user")
public class User {@TableIdprivate Long id;@TableField("nickname") // 映射到数据库字段 "nickname"private String name;private Integer age;private String email;@TableLogic(value = "0", delval = "1") // 逻辑删除字段private Integer deleted;
}

@OrderBy

该注解用于指定实体类中的字段在执行查询操作时的默认排序方式。如果没有显式指定排序条件,MyBatis-Plus 将按照注解中定义的排序规则返回结果。

@TableName("sys_user")
public class User {@TableIdprivate Long id;@TableField("nickname") // 映射到数据库字段 "nickname"private String name;@OrderBy(asc = false, sort = 10) // 指定默认排序为倒序,优先级为10private Integer age;private String email;
}

sort 数字越小,优先级越高,即越先被应用。

@OrderBy 注解的排序规则优先级低于在查询时通过 Wrapper 条件查询对象显式指定的排序条件。会被 Wrapper 指定的规则覆盖。

相关文章:

MybatisPlus 一些技巧

查询简化 SimpleQuery 有工具类 com.baomidou.mybatisplus.extension.toolkit.SimpleQuery 对 selectList 查询后的结果进行了封装&#xff0c;使其可以通过 Stream 流的方式进行处理&#xff0c;从而简化了 API 的调用。 方法 list() 支持对一个列表提取某个字段&#xff…...

定制化服务发现:Eureka中服务实例偏好的高级配置

定制化服务发现&#xff1a;Eureka中服务实例偏好的高级配置 在微服务架构中&#xff0c;服务实例的智能管理和优化是保证系统高效运行的关键。Eureka作为Netflix开源的服务注册与发现框架&#xff0c;提供了丰富的配置选项来满足不同场景下的需求。服务实例偏好配置允许开发者…...

【实战场景】MongoDB迁移的那些事

【实战场景】MongoDB迁移的那些事 开篇词&#xff1a;干货篇【MongoDB迁移的方法】&#xff1a;1. 基于mongodump和mongorestore的迁移一、迁移前准备二、使用mongodump备份数据三、使用mongorestore还原数据四、注意事项 2. 基于MongoDB复制集的迁移一、迁移前准备二、配置新复…...

为什么要使用加密软件?

一、保护数据安全&#xff1a;加密软件通过复杂的加密算法对敏感数据进行加密处理&#xff0c;使得未经授权的人员即使获取了加密数据&#xff0c;也无法轻易解密和获取其中的内容。这极大地提高了数据在存储、传输和使用过程中的安全性。 二、遵守法律法规&#xff1a;在许多国…...

k8s学习笔记——dashboard安装

重装了k8s集群后&#xff0c;重新安装k8s的仪表板&#xff0c;发现与以前安装不一样的地方。主要是镜像下载的问题&#xff0c;由于网络安全以及国外网站封锁的原因&#xff0c;现在很多镜像按照官方提供的仓库地址都下拉不下来&#xff0c;导致安装失败。我查了好几天&#xf…...

AI艺术创作:掌握Midjourney和DALL-E的技巧与策略

AI艺术创作&#xff1a;掌握Midjourney和DALL-E的技巧与策略 AI艺术创作正逐渐成为艺术家和创意工作者们探索新表达方式的重要工具。Midjourney和DALL-E是两款领先的AI绘画工具&#xff0c;它们各有独特的功能和优势。本文将详细介绍如何掌握这两款工具的使用技巧&#xff0c;…...

在Mac上免费恢复误删除的Word文档

Microsoft Word for Mac是一个有用的文字处理应用程序&#xff0c;它与Microsoft Office套件捆绑在一起。该软件的稳定版本包括 Word 2019、2016、2011 等。 Word for Mac 与 Apple Pages 兼容;这允许在不同的操作系统版本中使用Word文档&#xff0c;而不会遇到任何麻烦。 与…...

HarmonyOS 屏幕适配设计

1. armonyOS 屏幕适配设计 1.1. 像素单位 &#xff08;1&#xff09;px (Pixels)   px代表屏幕上的像素点&#xff0c;是手机屏幕分辨率的单位&#xff0c;即屏幕物理像素单位。 &#xff08;2&#xff09;vp (Viewport Percentage)   vp是视口百分比单位&#xff0c;基于…...

Netfilter之连接跟踪(Connection Tracking)和反向 SNAT(Reverse SNAT)

连接跟踪&#xff08;Connection Tracking&#xff09; 连接跟踪是 Netfilter 框架中的一个功能&#xff0c;用于跟踪网络连接的状态和元数据。它使防火墙能够识别和处理数据包属于哪个连接&#xff0c;并在双向通信中正确匹配请求和响应数据包。 工作原理 建立连接&#xf…...

Linux下使用vs code离线安装各种插件

Linux下使用vs code离线安装各种插件 &#xff08;1&#xff09;手动下载插件 插件市场 -> 搜索插件名 -> 右边栏 Download Extension &#xff08;2&#xff09;寻找安装目录 whereis code一般会出现两个目录&#xff0c;选择右边那个/usr/share/code code: /usr/b…...

【常见开源库的二次开发】基于openssl的加密与解密——Base58比特币钱包地址——算法分析(三)

目录&#xff1a; 目录&#xff1a; 一、base58(58进制) 1.1 什么是base58&#xff1f; 1.2 辗转相除法 1.3 base58输出字节数&#xff1a; 二、源码分析&#xff1a; 2.1源代码&#xff1a; 2.2 算法思路介绍&#xff1a; 2.2.1 Base58编码过程&#xff1a; 2.1.2 Base58解码过…...

Linux操作系统——数据库

数据库 sun solaris gnu 1、分类&#xff1a; 大型 中型 小型 ORACLE MYSQL/MSSQL SQLITE DBII powdb 关系型数据库 2、名词&#xff1a; DB 数据库 select update database DBMS 数据…...

【数据结构与算法】希尔排序:基于插入排序的高效排序算法

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 二、基本原理 三、实现步骤 四、C语言实现 五、性能分析 1. 时间复杂度…...

关于正点原子的alpha开发板的启动函数(汇编,自己的认识)

我傻逼了&#xff0c;这里的注释还是不要用&#xff1b; 全部换成 /* */ 这里就分为两块&#xff0c;一部分是复位中断部分&#xff0c;第二部分就是IRQ部分&#xff08;中断部分最重要&#xff09; 我就围绕着两部分来展开我的认识 首先声明全局 .global_start 在 ARM 架…...

Deep Layer Aggregation【方法部分解读】

摘要: 视觉识别需要跨越从低到高的层次、从小到大的尺度以及从精细到粗略的分辨率的丰富表示。即使卷积网络的特征层次很深,单独的一层信息也不足够:复合和聚合这些表示可以改进对“是什么”和“在哪里”的推断。架构上的努力正在探索网络骨干的许多维度,设计更深或更宽的架…...

大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】

大数据面试SQL题复习思路一网打尽&#xff01;(文档见评论区)_哔哩哔哩_bilibiliHive SQL 大厂必考常用窗口函数及相关面试题 大数据面试SQL题-笔记01【运算符、条件查询、语法顺序、表连接】大数据面试SQL题-笔记02【...】 目录 01、力扣网-sql题 1、高频SQL50题&#xff08…...

零基础自学爬虫技术该从哪里开始入手?

零基础自学爬虫技术可以从以下几个方面入手&#xff1a; 一、学习基础编程语言 Python 是爬虫开发的首选语言&#xff0c;因此首先需要学习 Python 编程语言的基础知识。这包括&#xff1a; 语法基础&#xff1a;学习 Python 的基本语法&#xff0c;如变量定义、数据类型、控…...

CV11_模型部署pytorch转ONNX

如果自己的模型中的一些算子&#xff0c;ONNX内部没有&#xff0c;那么需要自己去实现。 1.1 配置环境 安装ONNX pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple 安装推理引擎ONNX Runtime pip install onnxruntime -i https://pypi.tuna.tsinghua.edu.cn/si…...

Redis的使用(四)常见使用场景-缓存使用技巧

1.绪论 redis本质上就是一个缓存框架&#xff0c;所以我们需要研究如何使用redis来缓存数据&#xff0c;并且如何解决缓存中的常见问题&#xff0c;缓存穿透&#xff0c;缓存击穿&#xff0c;缓存雪崩&#xff0c;以及如何来解决缓存一致性问题。 2.缓存的优缺点 2.1 缓存的…...

BERT架构的深入解析

BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是由Google在2018年提出的一种基于Transformer架构的预训练模型&#xff0c;迅速成为自然语言处理&#xff08;NLP&#xff09;领域的一个里程碑。BERT通过双向编码器表示和预训练策略&am…...

YOLO12与YOLO11对比:新一代模型在精度和速度上有哪些提升?

YOLO12与YOLO11对比&#xff1a;新一代模型在精度和速度上有哪些提升&#xff1f; 1. 引言 目标检测技术作为计算机视觉领域的核心任务之一&#xff0c;其发展一直备受关注。YOLO(You Only Look Once)系列模型因其出色的实时性能而广受欢迎。2025年&#xff0c;Ultralytics推…...

Claude Code 接入 DeepSeek、GLM、MiniMax 等国产大模型,手把手带你起飞!

每天免费领 1亿 Token&#xff0c;白嫖DeepSeek、GLM、MiniMax、Kimi等大模型&#xff01; 这篇文章是专门写给那些想撸起袖子直接开干的朋友们的。咱们不整那些虚头巴脑的理论&#xff0c;核心就帮大家解决四件事&#xff1a;搞定 Claude Code 的安装、确认这玩意儿能跑通、成…...

极简配置:OpenClaw快速接入Phi-3-mini-128k-instruct的HTTP接口

极简配置&#xff1a;OpenClaw快速接入Phi-3-mini-128k-instruct的HTTP接口 1. 为什么选择Phi-3-mini-128k-instruct 上周我在调试一个自动化文档处理流程时&#xff0c;发现现有的大模型响应速度跟不上我的实时需求。经过几轮测试&#xff0c;最终选择了微软开源的Phi-3-min…...

主流信道模型对比:从COST207到WINNER II的多场景性能解析

1. 信道模型的前世今生&#xff1a;为什么我们需要这么多标准&#xff1f; 第一次接触信道模型时&#xff0c;我也被各种COST、WINNER之类的缩写搞晕了。这就像去超市买酱油&#xff0c;发现货架上摆着生抽、老抽、海鲜酱油、薄盐酱油...其实它们都是为了解决不同场景下的调味需…...

STM32F103C8T6 RAM不够用?手把手教你用CAN总线实现边收边写的IAP升级(附完整代码)

STM32F103C8T6 RAM资源紧张&#xff1f;CAN总线流式IAP方案实战解析 对于使用STM32F103C8T6这类RAM资源有限的MCU开发者来说&#xff0c;实现远程固件升级(IAP)功能时常常面临内存不足的困扰。这款经典Cortex-M3芯片仅有20KB RAM&#xff0c;传统方案需要预留大量缓冲区存储完整…...

5分钟快速上手MUNIT:从零开始构建你的第一个图像翻译模型

5分钟快速上手MUNIT&#xff1a;从零开始构建你的第一个图像翻译模型 【免费下载链接】MUNIT Multimodal Unsupervised Image-to-Image Translation 项目地址: https://gitcode.com/gh_mirrors/mu/MUNIT MUNIT&#xff08;Multimodal Unsupervised Image-to-Image Trans…...

SEO_资深运营揭秘,长期稳定排名的SEO策略介绍

SEO策略的核心要素&#xff1a;内容质量 在资深运营者的经验中&#xff0c;内容质量始终是SEO策略的核心要素。一个优质的网站&#xff0c;首先需要提供高质量、有价值的内容&#xff0c;这不仅能吸引用户&#xff0c;还能提升网站在搜索引擎中的排名。长期稳定的SEO排名离不开…...

Mac电脑免费小龙虾OpenClaw+Ollama使用心得

一、前言 很多人以为本地部署OpenClaw小龙虾&#xff08;原始版&#xff09;不管是调用国外大模型还是国内大模型&#xff0c;都要付费才能使用&#xff0c;并且如果是需要大耗量的token调用操作费用还不便宜。加上最近新闻发布的“龙虾”安全问题&#xff0c;因此很多人是望而…...

C语言宏定义封装函数参数的工程实践

1. 宏定义封装函数参数的核心价值在嵌入式开发中&#xff0c;我们经常遇到需要传递大量固定参数的场景。以NXP RT1052 SDK中的GPIO配置为例&#xff0c;每个引脚复用配置需要传递6个参数&#xff0c;其中5个都是固定值。这种场景下&#xff0c;宏定义封装技术能显著提升代码的可…...

Threejs 使用Line2实现自定义线条宽度的实战指南

1. 为什么Three.js默认的lineWidth设置无效&#xff1f; 很多Three.js开发者第一次尝试修改线条宽度时&#xff0c;都会遇到一个令人困惑的问题&#xff1a;明明设置了lineWidth属性&#xff0c;但渲染出来的线条始终是1像素宽。这个问题其实源于WebGL的底层限制。WebGL基于Ope…...