MybatisPlus 一些技巧

news/2024/9/17 19:04:40/ 标签: java, 数据库

查询简化

SimpleQuery

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

方法 list()

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

java">// 假设有一个 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。

java">// 假设有一个 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。可以用于如字典的这种情况。

java">// 假设有一个 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 进行进一步处理。

java">// 假设有一个 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 的方式:

java">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 的方式:

java">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 版本

java">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

java">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 片段到查询条件中。

java">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 的查询优化。

java">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 片段。

java">// 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在数据库中存储枚举值的哪个属性。

java">@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 会自动将逻辑删除字段的值更新为逻辑删除值,而不是物理删除记录。

java">@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 将按照注解中定义的排序规则返回结果。

java">@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 指定的规则覆盖。


http://www.ppmy.cn/news/1474538.html

相关文章

Hadoop简明教程

文章目录 关于HadoopHadoop拓扑结构Namenode 和 Datanode 基本管理启动Hadoop启动YARN验证Hadoop服务停止Hadoop停止HDFS Hadoop集群搭建步骤准备阶段Java环境配置Hadoop安装与配置HDFS格式化与启动服务测试集群安装额外组件监控与维护&#xff1a; 使用Docker搭建集群使用Hado…

如何确保 PostgreSQL 在高并发写操作场景下的数据完整性?

文章目录 一、理解数据完整性二、高并发写操作带来的挑战三、解决方案&#xff08;一&#xff09;使用合适的事务隔离级别&#xff08;二&#xff09;使用合适的锁机制&#xff08;三&#xff09;处理死锁&#xff08;四&#xff09;使用索引和约束&#xff08;五&#xff09;批…

如何在 Objective-C 中实现多态性,并且它与其他面向对象编程语言的多态性实现有何差异?

在Objective-C中&#xff0c;多态性可以通过使用父类的指针来调用子类的方法来实现。具体来说&#xff0c;可以定义一个父类的指针&#xff0c;然后将子类的实例赋值给这个指针。这样&#xff0c;即使使用父类的指针来调用方法&#xff0c;实际上会调用子类的方法。 需要注意的…

2024.7.11 刷题总结

2024.7.11 **每日一题** 2972.统计移除递增子数组的数目 Ⅱ&#xff0c;这道题和昨天的前置题目思路完全一样&#xff0c;只是数据范围变大了。我们还是先处理最大上升前缀&#xff0c;并且加上答案。然后从最后一个元素开始遍历&#xff0c;直到出现非下降元素就终止&#xff…

Elon Musk开源Grok

转载自&#xff1a;AILab基地 早在6天前&#xff0c;马斯克就发文称xAI将开源Grok 图片 13小时前&#xff0c;马斯克开源了旗下公司X的Grok训练模型&#xff0c;并喊话OpenAI&#xff0c;你名字里的Open到底在哪里 图片 下面是xai-org的GitHub开源地址[https://github.com/x…

羧基聚乙二醇生物素的制备方法;COOH-PEG-Biotin

羧基聚乙二醇生物素&#xff08;COOH-PEG-Biotin&#xff09;是一种常见的生物分子聚合物&#xff0c;具有多种应用&#xff0c;特别是在生物实验、药物研发和生物技术等领域。以下是对该化合物的详细解析&#xff1a; 一、基本信息 名称&#xff1a;羧基聚乙二醇生物素&#x…

钉钉扫码登录第三方

钉钉文档 实现登录第三方网站 - 钉钉开放平台 (dingtalk.com) html页面 将html放在 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>登录</title>// jquery<script src"http://code.jqu…

网络(一)——初始网络

文章目录 计算机网络的背景网络发展认识 "协议" 网络协议初识协议分层网络分层 网络传输基本流程数据包封装和分用网络中的地址管理认识IP地址认识MAC地址 计算机网络的背景 网络发展 独立模式:计算机之间相互独立 在最早的时候&#xff0c;计算机之间是相互独立的&…

EasyExcel文档链接与使用示例

文档链接 注解 https://blog.csdn.net/estelle_belle/article/details/134508223 官方文档地址 https://github.com/alibaba/easyexcel/tree/master?tabreadme-ov-file 使用示例 依赖版本 <dependency><groupId>com.alibaba</groupId><artifactId>…

【爬虫入门知识讲解:xpath】

3.3、xpath xpath在Python的爬虫学习中&#xff0c;起着举足轻重的地位&#xff0c;对比正则表达式 re两者可以完成同样的工作&#xff0c;实现的功能也差不多&#xff0c;但xpath明显比re具有优势&#xff0c;在网页分析上使re退居二线。 xpath 全称为XML Path Language 一种…

玄机——第五章 linux实战-黑链 wp

文章目录 一、前言二、概览简介 三、参考文章四、步骤&#xff08;解析&#xff09;准备步骤#1.0步骤#1.1找到黑链添加在哪个文件 flag 格式 flag{xxx.xxx} 步骤#1.2webshell的绝对路径 flag{xxxx/xxx/xxx/xxx/} 步骤#1.3黑客注入黑链文件的 md5 md5sum file flag{md5} 步骤#1.…

Mysql LIKE什么时候走索引,什么时候不走索引

在 MySQL 中&#xff0c;LIKE 查询是否走索引&#xff0c;主要取决于通配符的位置和使用的存储引擎。 使用索引的情况 前缀匹配&#xff1a; 当 LIKE 查询中的通配符出现在字符串的末尾时&#xff0c;查询可以利用索引。例如&#xff0c;LIKE abc% 。这种情况下&#xff0c;索…

如何使用Python正则表达式解析多行文本

使用 Python 的正则表达式来解析多行文本通常涉及到使用多行模式&#xff08;re.MULTILINE&#xff09;和 re.DOTALL 标志&#xff0c;以及适当的正则表达式模式来匹配你想要提取或处理的文本块。以下是一个简单的示例&#xff0c;展示了如何处理多行文本&#xff1a; 1、问题背…

基于EMQX+Flask+InfluxDB+Grafana打造多协议物联网云平台:MQTT/HTTP设备接入与数据可视化流程(附代码示例)

摘要: 本文深入浅出地介绍了物联网、云平台、MQTT、HTTP、数据可视化等核心概念&#xff0c;并结合 EMQX、Flask、InfluxDB、Grafana 等主流工具&#xff0c;手把手教你搭建一个支持多协议的物联网云平台。文章结构清晰&#xff0c;图文并茂&#xff0c;代码翔实易懂&#xff0…

MySQL 数据库的 DDL

备份 MySQL 数据库的 DDL&#xff08;数据定义语言&#xff09;语句包括导出数据库结构&#xff08;如表、视图、触发器、存储过程和函数等&#xff09;&#xff0c;但不包括实际数据。通常使用 mysqldump 工具进行此类操作。以下是具体的方法&#xff1a; 备份 DDL 1. 导出数…

免费的AI文生视频哪些比较靠谱?

目前市场上推出了很多文生图&#xff0c;图生视频等各类AI工具网站&#xff0c;但实际上效果如何呢&#xff1f; 可以说&#xff0c;进步很大。从无到有&#xff0c;从有到精&#xff0c;毕竟需要一个时间阶段的。 国内的文生视频大部分都直接需要付费&#xff0c;不付费的比…

近期几首小诗汇总-生活~卷

生活 为生活飘零&#xff0c;风雨都不阻 路见盲人艰&#xff0c;为她心点灯 贺中科大家长论坛成立十五周年 科学家园有喜贺 园外丑汉翘望中 曾一学子入我科 正育科二盼长大 憧憬也能入此家 与科学家论短长 园外翘首听高论 发现有隙入此坛 竟然也能注册成 入园浏览惶然立 此贴…

clean code-代码整洁之道 阅读笔记(第十六章)

第十六章 重构SerialDate 16.1 首先&#xff0c;让它能工作 利用SerialDateTests来完整的理解和重构SerialDate用Clover来检查单元测试覆盖了哪些代码&#xff0c;效果不行重新编写自己的单元测试经过简单的修改&#xff0c;让测试能够通过 16.2 让它做对 全过程&#xff1…

【Go系列】 array、slice 和 map

承上启下 我们上一篇文章中介绍了if和for&#xff0c;这不得练习下&#xff0c;让我们一起来实践一下如何使用 continue 语句来计算100以内的偶数之和。在我们编写代码的过程中&#xff0c;continue 语句将会帮助我们跳过某些不需要的迭代&#xff0c;比如在这个例子中&#xf…

RabbitMQ 高级功能

RabbitMQ 是一个广泛使用的开源消息代理&#xff0c;它支持多种消息传递协议&#xff0c;可以在分布式系统中用于可靠的消息传递。除了基本的消息队列功能外&#xff0c;RabbitMQ 还提供了一些高级功能&#xff0c;增强了其在高可用性、扩展性和灵活性方面的能力。以下是一些主…