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

MyBatis-Plus联表查询的短板,该如何解决呢

mybatis-plus作为mybatis的增强工具,它的出现极大的简化了开发中的数据库操作,但是长久以来,它的联表查询能力一直被大家所诟病。一旦遇到left join或right join的左右连接,你还是得老老实实的打开xml文件,手写上一大段的sql语句。

直到前几天,偶然碰到了这么一款叫做mybatis-plus-join的工具(后面就简称mpj了),使用了一下,不得不说真香!彻底将我从xml地狱中解放了出来,终于可以以类似mybatis-plus中QueryWrapper的方式来进行联表查询了,话不多说,我们下面开始体验。

1 引入依赖

首先在项目中引入引入依赖坐标,因为mpj中依赖较高版本mybatis-plus中的一些api,所以项目建议直接使用高版本。

<dependency><groupId>com.github.yulichang</groupId><artifactId>mybatis-plus-join</artifactId><version>1.2.4</version>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version>
</dependency>

引入相关依赖后,在springboot项目中,像往常一样正常配置数据源连接信息就可以了。

2 数据准备

因为要实现联表查询,所以我们先来建几张表进行测试。

订单表:

用户表,包含用户姓名:

商品表,包含商品名称和单价:

在订单表中,通过用户id和商品id与其他两张表进行关联。

3 修改Mapper

以往在使用myatis-plus的时候,我们的Mapper层接口都是直接继承的BaseMapper,使用mpj后需要对其进行修改,改为继承MPJBaseMapper接口。

@Mapper
public interface OrderMapper extends MPJBaseMapper<Order> {
}

对其余两个表的Mapper接口也进行相同的改造。此外,我们的service也可以选择继承MPJBaseService,serviceImpl选择继承MPJBaseServiceImpl,这两者为非必须继承。

4 查询

Mapper接口改造完成后,我们把它注入到Service中,虽然说我们要完成3张表的联表查询,但是以Order作为主表的话,那么只注入这一个对应的OrderMapper就可以,非常简单。

@Service
@AllArgsConstructor
public class OrderServiceImpl implements OrderService {private final OrderMapper orderMapper;
}

4.1使用MPJLambdaWrapper进行联表查询

接下来,我们体验一下再也不用写sql的联表查询:

public void getOrder() {List<OrderDto> list = orderMapper.selectJoinList(OrderDto.class,new MPJLambdaWrapper<Order>().selectAll(Order.class).select(Product::getUnitPrice).selectAs(User::getName,OrderDto::getUserName).selectAs(Product::getName,OrderDto::getProductName).leftJoin(User.class, User::getId, Order::getUserId).leftJoin(Product.class, Product::getId, Order::getProductId).eq(Order::getStatus,3));list.forEach(System.out::println);
}

不看代码,我们先调用接口来看一下执行结果:

可以看到,成功查询出了关联表中的信息,下面我们一点点介绍上面代码的语义。

首先,调用mapper的selectJoinList()方法,进行关联查询,返回多条结果。后面的第一个参数OrderDto.class代表接收返回查询结果的类,作用和我们之前在xml中写的resultType类似。

这个类可以直接继承实体,再添加上需要在关联查询中返回的列即可:

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class OrderDto extends Order {String userName;String productName;Double unitPrice;
}

接下来的MPJLambdaWrapper就是构建查询条件的核心了,看一下我们在上面用到的几个方法:

  • selectAll():查询指定实体类的全部字段

  • select():查询指定的字段,支持可变长参数同时查询多个字段,但是在同一个select中只能查询相同表的字段,所以如果查询多张表的字段需要分开写

  • selectAs():字段别名查询,用于数据库字段与接收结果的dto中属性名称不一致时转换

  • leftJoin():左连接,其中第一个参数是参与联表的表对应的实体类,第二个参数是这张表联表的ON字段,第三个参数是参与联表的ON的另一个实体类属性

除此之外,还可以正常调用mybatis-plus中的各种原生方法,文档中还提到,默认主表别名是t,其他的表别名以先后调用的顺序使用t1、t2、t3以此类推。

我们用插件读取日志转化为可读的sql语句,可以看到两条左连接条件都被正确地添加到了sql中:

4.2 使用MPJQueryWrapper进行联表查询

和mybatis-plus非常类似,除了LamdaWrapper外还提供了普通QueryWrapper的写法,改造上面的代码:

public void getOrderSimple() {List<OrderDto> list = orderMapper.selectJoinList(OrderDto.class,new MPJQueryWrapper<Order>().selectAll(Order.class).select("t2.unit_price","t2.name as product_name").select("t1.name as user_name").leftJoin("t_user t1 on t1.id = t.user_id").leftJoin("t_product t2 on t2.id = t.product_id").eq("t.status", "3"));list.forEach(System.out::println);
}

运行结果与之前完全相同,需要注意的是,这样写时在引用表名时不要使用数据库中的原表名,主表默认使用t,其他表使用join语句中我们为它起的别名,如果使用原表名在运行中会出现报错。

并且,在MPJQueryWrapper中,可以更灵活的支持子查询操作,如果业务比较复杂,那么使用这种方式也是不错的选择。

5 分页查询

mpj中也能很好的支持列表查询中的分页功能,首先我们要在项目中加入分页拦截器:

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));return interceptor;
}

接下来改造上面的代码,调用selectJoinPage()方法:

public void page() {IPage<OrderDto> orderPage = orderMapper.selectJoinPage(new Page<OrderDto>(2,10),OrderDto.class,new MPJLambdaWrapper<Order>().selectAll(Order.class).select(Product::getUnitPrice).selectAs(User::getName, OrderDto::getUserName).selectAs(Product::getName, OrderDto::getProductName).leftJoin(User.class, User::getId, Order::getUserId).leftJoin(Product.class, Product::getId, Order::getProductId).orderByAsc(Order::getId));orderPage.getRecords().forEach(System.out::println);
}

注意在这里需要添加一个分页参数的Page对象,我们再执行上面的代码,并对日志进行解析,查看sql语句:

可以看到底层通过添加limit进行了分页,同理,MPJQueryWrapper也可以这样进行分页。

6 最后总结

经过简单的测试,个人感觉mpj这款工具在联表查询方面还是比较实用的,能更应对项目中不是非常复杂的场景下的sql查询,大大提高我们的生产效率。当然,在项目的issues中也能看到当前版本中也仍然存在一些问题,希望在后续版本迭代中能继续完善。

相关文章:

MyBatis-Plus联表查询的短板,该如何解决呢

mybatis-plus作为mybatis的增强工具&#xff0c;它的出现极大的简化了开发中的数据库操作&#xff0c;但是长久以来&#xff0c;它的联表查询能力一直被大家所诟病。一旦遇到left join或right join的左右连接&#xff0c;你还是得老老实实的打开xml文件&#xff0c;手写上一大段…...

吲哚菁绿-巯基,ICG-SH,科研级别试剂,吲哚菁绿可用于测定心输出量、肝脏功能、肝血流量,和对于眼科血管造影术。

ICG-THIOL,吲哚菁绿-巯基 中文名称&#xff1a;吲哚菁绿-巯基 英文名称&#xff1a;ICG-THIOL 英文别名&#xff1a;ICG-SH 性状&#xff1a;绿色粉末 溶剂&#xff1a;溶于二氯甲烷等其他常规有机溶剂 稳定性&#xff1a;冷藏保存&#xff0c;避免反复冻融。 存储条件&…...

深度剖析JavaOptional类

Java Optional 类 Optional类在 Java 8中被加了进来,提供了一种处理业务逻辑想要的值可能没有出现(null)也可能出现的情况,可能直到目前,我们还是用null 来表示业务值不存在的情况,但是这可能导致空指针异常,Java 8新添加 Optional类可以从一定程度上来解决这个问题。 O…...

平面设计软件Corel CDR2023又开始放大招啦,CorelDRAW Graphics Suite 2023有哪些新增功能?

CorelDRAW 2023中文版即将于2023年3月14日&#xff0c;在苏州举行线上直播的2023新品发布会&#xff0c;本次发布会主题为“设计新生力&#xff0c;矢量新未来”。 发布会邀请思杰马克丁公司领导、Corel 中国区总经理分享思杰与 Corel 的合作模式及在 CorelDRAW 产品上推动历程…...

初学torch【报错:expected scalar type double but found float、rmse】

目录 一、inout 二、expected scalar type double but found float 报错 三、pytorch中回归评价rmse&#xff1a; 一、inout torch网络训练&#xff0c;输入需要转换为tensor格式&#xff1a; import torch import numpy A torch.arange(12, dtypetorch.float32).reshape((…...

金三银四、金九银十 面试宝典 JAVASE八股文面试题 超级无敌全的面试题汇总(接近3万字的面试题,让你的JAVA语法基础无可挑剔)

JavaSE八股文 - 面试宝典 一个合格的 计算机打工人 &#xff0c;收藏夹里必须有一份 JAVA八股文面试题 &#xff0c;特别是即将找工作的计算机人&#xff0c;希望本篇博客对你有帮助&#xff01; 本文参考了诸多大佬的面试题帖子&#xff0c;ps&#xff1a;白大锅、哪吒、英雄…...

数据结构:链式二叉树初阶

目录 一.链式二叉树的逻辑结构 1.链式二叉树的结点结构体定义 2.链式二叉树逻辑结构 二.链式二叉树的遍历算法 1.前序遍历 2.中序遍历 3.后序遍历 4.层序遍历(二叉树非递归遍历算法) 层序遍历概念: 层序遍历算法实现思路: 层序遍历代码实现: 三.链式二叉树遍历算…...

公式编写1000问9-12

9.问: 买入&#xff1a;日线创100日新高 ,周线(5周&#xff09;BIAS>10 卖出&#xff1a;2日收盘在30线下方 注&#xff1a;买卖都只要单一信号即可&#xff0c;不要连续给出信号 我今天才开始学习编写&#xff0c;可是没有买入信号&#xff0c;不知道哪错了&#xff1f; B1…...

C++11:类的新功能和可变参数模板

文章目录1. 新增默认成员函数1.1 功能1.2 示例2. 类成员变量初始化3. 新关键字3.1 关键字default3.2 关键字delete补充3.3 关键字final和override4. 可变参数模板4.1 介绍4.2 定义方式4.3 展开参数包递归展开参数包优化初始化列表展开参数包逗号表达式展开参数包补充5. emplace…...

【Java学习笔记】15.Java 日期时间(1)

Java 日期时间 java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象。 第一个构造函数使用当前日期和时间来初始化对象。 Date( )第二个构造函数接收一个参数&#xff0c;该参数是从 1970 年 1 月 1 日起的毫秒数。 Date(long …...

在ROS2中,通过MoveIt2控制Gazebo中的自定义机械手

目前的空余时间主要都在研究ROS2&#xff0c;最终目的是控制自己用舵机组装的机械手。 由于种种原因&#xff0c;先控制Gazebo的自定义机械手。 先看看目前的成果 左侧是rviz2中的moveit组件的机械手&#xff0c;右侧是gazebo中的机械手。在moveit中进行路径规划并执行后&#…...

Java-线程池 原子性 类

Java-线程池 原子性 类线程池构造方法调用Executors静态方法创建调用方法直接创建线程池对象原子性volatile-问题出现原因:volatile解决原子性AtomicInteger的常用方法悲观锁和乐观锁synchronized(悲)和CAS(乐)的区别并发工具类Hashtable集合ConcurrentHashMap原理:CountDownLa…...

力扣sql简单篇练习(二十五)

力扣sql简单篇练习(二十五) 1 无效的推文 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT tweet_id FROM Tweets WHERE CHAR_LENGTH(content)>151.3 运行截图 2 求关注者的数量 2.1 基本题目内…...

计算机网络:OSPF协议和链路状态算法

OSPF协议 开放最短路经优先OSPF协议是基于最短路径算法SPF,其主要特征就是使用分布式的链路状态协议OSPF协议的特点&#xff1a; 1.使用泛洪法向自治系统中的所有路由器发送信息&#xff0c;即路由器通过输出端口向所有相邻的路由器发送信息&#xff0c;而每一个相邻的路由器又…...

利用表驱动法+策略模式优化switch-case

1.前言 我有一个需求&#xff1a;有四个系统需要处理字段&#xff0c;一开始利用switch-case进行区分编码&#xff0c;后期字段处理越来越多&#xff0c;导致switch-case代码冗余&#xff0c;不太好&#xff0c;然后想通过java单继承多实现的性质进行优化。 2.实现 2.1定义S…...

SpringBoot创建和使用

目录 什么是SpringBoot SpringBoot的优点 SpringBoot项目的创建 1、使用idea创建 2、项目目录介绍和运行 Spring Boot配置文件 1、配置文件 2、配置文件的格式 3、properties 3.1、properties基本语法 3.2、读取配置文件 3.3、缺点 4、yml 4.1、优点 4.2、yml基本…...

which、whereis、locate文件查找命令

Linux下查找文件的命令有which、whereis、locate和find&#xff0c;find命令因要遍历文件系统&#xff0c;导致速度较慢&#xff0c;而且还会影响系统性能&#xff0c;而且命令选项较多&#xff0c;就单独放一篇介绍&#xff0c;可参见find命令——根据路径和条件搜索指定文件_…...

Uipath Excel 自动化系列14-SaveExcelFile(保存Excel)

活动描述 SaveExcelFile 保存Excel:保存工作簿&#xff0c;在修改 Excel 文件的用户界面自动化活动之后使用此活动&#xff0c;以保存对文件的更改 SaveExcelFile As 另存Excel : 将workbook 另存为文件 SaveExcelFile As PDF &#xff1a;将Excel 另存为PDF文件。该三个活…...

MyBatis学习

MyBatis优点 轻量级&#xff0c;性能出色 SQL 和 Java 编码分开&#xff0c;功能边界清晰。Java代码专注业务、SQL语句专注数据 开发效率稍逊于HIbernate&#xff0c;但是完全能够接受 补充&#xff1a;POJO 一&#xff1a;什么是POJO POJO的名称有多种&#xff0c;pure old…...

高速PCB设计指南系列(二)

第三篇 高速PCB设计 &#xff08;一&#xff09;、电子系统设计所面临的挑战   随着系统设计复杂性和集成度的大规模提高&#xff0c;电子系统设计师们正在从事100MHZ以上的电路设计&#xff0c;总线的工作频率也已经达到或者超过50MHZ&#xff0c;有的甚至超过100MHZ。目前…...

电商老板必看:用Excel的IF和VLOOKUP函数,轻松算出你的新老客户利润贡献比

电商精细化运营&#xff1a;用Excel透视新老客户利润贡献的实战指南 对于中小电商企业主来说&#xff0c;理解客户结构是精细化运营的第一步。你可能没有专业的BI工具&#xff0c;但Excel这个看似普通的办公软件&#xff0c;却能帮你挖掘出惊人的商业洞察。本文将带你一步步构建…...

团队协作中的Git分支管理:为什么我们最终放弃了Rebase?

团队协作中的Git分支管理&#xff1a;为什么我们最终放弃了Rebase&#xff1f; 当我们的技术团队从5人扩展到20人时&#xff0c;Git仓库的提交历史突然变成了需要考古学家破译的楔形文字。最初被Rebase的"整洁线性历史"吸引的我们&#xff0c;在经历三个月的实践后&a…...

Keil uVision5与STC8H单片机开发实战:手把手教你搭建第一个项目

Keil uVision5与STC8H单片机开发实战&#xff1a;从零搭建完整项目框架 作为一名长期从事嵌入式开发的工程师&#xff0c;我深知初学者在迈出第一步时面临的困惑。本文将带你完整走一遍STC8H单片机在Keil uVision5环境下的项目搭建流程&#xff0c;不仅包含基础操作&#xff0c…...

OpenLiteSpeed实战踩坑记录:为什么我最终回归了LNMP环境?

OpenLiteSpeed实战反思&#xff1a;为什么复杂WordPress环境更适合LNMP&#xff1f; 最近在技术社区里&#xff0c;OpenLiteSpeed被频繁提及&#xff0c;尤其是它宣称的高性能PHP处理能力吸引了不少WordPress站长的注意。作为一个长期使用LNMP环境的开发者&#xff0c;我也被这…...

RePKG:解锁Wallpaper Engine资源宝库的终极提取与转换工具

RePKG&#xff1a;解锁Wallpaper Engine资源宝库的终极提取与转换工具 【免费下载链接】repkg Wallpaper engine PKG extractor/TEX to image converter 项目地址: https://gitcode.com/gh_mirrors/re/repkg RePKG 是一款专为Wallpaper Engine设计的开源C#工具&#xff…...

别再把FastAPI路由和挂载搞混了!一张图讲清`mount`与子应用的应用场景

FastAPI路由与挂载深度解析&#xff1a;如何为模块化开发选择最佳方案 在构建现代Web应用时&#xff0c;模块化设计已成为提升可维护性和团队协作效率的关键策略。FastAPI作为Python生态中最受欢迎的异步框架之一&#xff0c;提供了两种截然不同的模块化方案&#xff1a;APIRo…...

8公里巷道,最小误差仅0.6%,天宝耐特携L2pro解锁矿山井下高效安全测量

随着数字矿山建设的加速推进&#xff0c;空间数据采集技术成为矿山数字化转型的重要支撑。在此背景下&#xff0c;天宝耐特在华南某大型金矿完成了灵光L2pro手持SLAM三维激光扫描技术的深度应用实践&#xff0c;以硬核技术破解矿山作业难题&#xff0c;实现井下数字孪生底座构建…...

飞机表面缺陷识别分割数据集labelme格式4612张5类别

注意数据集中有超过一半图片是增强图片数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件)图片数量(jpg文件个数)&#xff1a;4612标注数量(json文件个数)&#xff1a;4612标注类别数&#xff1a;5标注类别名称:["Crack"…...

如何在广告泛滥的时代找到纯粹的音乐净土?铜钟音乐的极简听歌方案

如何在广告泛滥的时代找到纯粹的音乐净土&#xff1f;铜钟音乐的极简听歌方案 【免费下载链接】tonzhon-music 铜钟 (Tonzhon.com): 免费听歌; 没有直播, 社交, 广告, 干扰; 简洁纯粹, 资源丰富, 体验独特&#xff01;(密码重置功能已回归) 项目地址: https://gitcode.com/Gi…...

用PyTorch复现掌纹识别顶会论文:从VGG16到ResNet152的模型蒸馏踩坑实录

从VGG16到ResNet152&#xff1a;掌纹识别模型蒸馏实战中的关键挑战与解决方案 掌纹识别作为生物特征识别领域的重要分支&#xff0c;近年来在深度学习技术的推动下取得了显著进展。然而&#xff0c;当我们将论文中的理论模型转化为实际可运行的代码时&#xff0c;往往会遇到一系…...