mybatis-plus 使用 mybatis-plus-join 增强多表关联查询能力

一、mybatis-plus-join

mybatis-plus 原生的能力不支持多表关联,对于这种场景只能通过写SQL进行实现,而mybatis-plus-join 则是建立在 mybatis-plus 基础之上的扩展框架,可以在不影响原有能力之上通过简单的API即可实现多表关联能力而无需编写SQL

官方仓库地址:https://gitee.com/best_handsome/mybatis-plus-join

官方文档:https://mybatisplusjoin.com/pages/quickstart/js.html

二、mybatis-plus-join 实践

新建测试表结构:

CREATE TABLE `user` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`age` int DEFAULT NULL,`email` varchar(255) DEFAULT NULL,`username` varchar(255) DEFAULT NULL,`password` varchar(255) DEFAULT NULL,`status` int DEFAULT NULL,`delete_flag` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `role` (`id` int NOT NULL AUTO_INCREMENT,`role_name` varchar(255) DEFAULT NULL,`desc` varchar(255) DEFAULT NULL,`delete_flag` varchar(255) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;CREATE TABLE `user_role_mapping` (`id` int NOT NULL AUTO_INCREMENT,`user_id` int DEFAULT NULL,`role_id` int DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

写入测试数据:

INSERT INTO `test1`.`user` (`id`, `name`, `age`, `email`, `username`, `password`, `status`, `delete_flag`) VALUES (1, '张三', 15, 'zhangsan@test.com', 'zhangsan', '123', 1, '0');
INSERT INTO `test1`.`user` (`id`, `name`, `age`, `email`, `username`, `password`, `status`, `delete_flag`) VALUES (2, '李四', 16, 'lisi@test.com', 'lisi', '123', 1, '0');
INSERT INTO `test1`.`user` (`id`, `name`, `age`, `email`, `username`, `password`, `status`, `delete_flag`) VALUES (3, '王五', 15, 'wangwu@test.com', 'wangwu', '123', 1, '0');
INSERT INTO `test1`.`user` (`id`, `name`, `age`, `email`, `username`, `password`, `status`, `delete_flag`) VALUES (4, '李六', 18, 'liliu@test.com', 'liliu', '123', 1, '0');
INSERT INTO `test1`.`user` (`id`, `name`, `age`, `email`, `username`, `password`, `status`, `delete_flag`) VALUES (5, '小红', 15, 'xiaohong@test.com', 'xiaohong', '123', 1, '0');
INSERT INTO `test1`.`user` (`id`, `name`, `age`, `email`, `username`, `password`, `status`, `delete_flag`) VALUES (6, '小明', 19, 'xiaoming@test.com', 'xiaoming', '123', 1, '0');
INSERT INTO `test1`.`user` (`id`, `name`, `age`, `email`, `username`, `password`, `status`, `delete_flag`) VALUES (7, '小张', 15, 'xiaozhang@test.com', 'xiaozhang', '123', 1, '0');INSERT INTO `test1`.`role` (`id`, `role_name`, `desc`, `delete_flag`) VALUES (1, 'admin', '管理员', '0');
INSERT INTO `test1`.`role` (`id`, `role_name`, `desc`, `delete_flag`) VALUES (2, 'root', '超级管理员', '0');
INSERT INTO `test1`.`role` (`id`, `role_name`, `desc`, `delete_flag`) VALUES (3, 'common', '普通人', '0');
INSERT INTO `test1`.`role` (`id`, `role_name`, `desc`, `delete_flag`) VALUES (4, 'leader', '组长', '0');INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (1, 1, 1);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (2, 2, 1);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (3, 3, 3);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (4, 4, 3);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (5, 5, 4);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (6, 6, 4);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (7, 7, 3);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (8, 1, 2);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (9, 1, 4);
INSERT INTO `test1`.`user_role_mapping` (`id`, `user_id`, `role_id`) VALUES (10, 2, 4);

下面新建 SpringBoot 项目,在 pom 中引入以下依赖:

<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version>
</dependency><dependency><groupId>com.github.yulichang</groupId><artifactId>mybatis-plus-join-boot-starter</artifactId><version>1.4.7</version>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.6</version>
</dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>

application.yml 配置信息如下:

server:port: 8010spring:datasource:url: jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMTusername: rootpassword: roottype: com.alibaba.druid.pool.DruidDataSource
mybatis-plus:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.bxc.mybatisplusjoin.domain.entityconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: trueglobal-config:db-config:logic-delete-field: deleteFlag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)logic-delete-value: 1 # 逻辑已删除值(默认为 1)logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)mybatis-plus-join:#是否打印 mybatis plus join banner 默认truebanner: true#全局启用副表逻辑删除(默认true) 关闭后关联查询不会加副表逻辑删除sub-table-logic: true#拦截器MappedStatement缓存(默认true)ms-cache: true#表别名(默认 t)table-alias: t#副表逻辑删除条件的位置,支持where、on默认 where (1.4.4+)logic-del-type: where

启动类上增加 mapper 扫描注解:

@MapperScan("com.bxc.mybatisplusjoin.mapper")

下面通过 MyBatisX 生成 entity、mapper、service,不了解 MyBatisX 可以参考下面链接:

https://baomidou.com/pages/ba5b24/

在这里插入图片描述
在这里插入图片描述

生成的代码是基于原生的 mybatis-plus 的,需要简单修改下:

首先对于 mapper 将继承 BaseMapper 替换成 MPJBaseMapper

在这里插入图片描述
使用此方式修改其他 mapper,然后对于 service,将继承 IService 替换成 MPJBaseService

在这里插入图片描述

同样对于 Impl 实现也需要将 ServiceImpl 需改为 MPJBaseServiceImpl

在这里插入图片描述

下面就可以进行关联查询了:

例如:查询用户和角色信息

先创建 vo 类:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRoleVO {private Long userId;private String name;private Long roleId;private String roleName;}

关联查询

@Slf4j
@SpringBootTest
class MybatisPlusJoinApplicationTests {@ResourceUserService userService;// 查询用户和角色信息@Testvoid contextLoads() {List<UserRoleVO> userRoleVOS = userService.selectJoinList(UserRoleVO.class,new MPJLambdaWrapper<User>().select(User::getId, User::getName).selectAs(User::getId, UserRoleVO::getUserId).selectAs(User::getName, UserRoleVO::getName).innerJoin(UserRoleMapping.class, UserRoleMapping::getUserId, User::getId).innerJoin(Role.class, Role::getId, UserRoleMapping::getRoleId).select(Role::getId, Role::getRoleName).selectAs(Role::getId, UserRoleVO::getRoleId).selectAs(Role::getRoleName, UserRoleVO::getRoleName));userRoleVOS.forEach(vo-> log.info(vo.toString()));}}

运行结果:

在这里插入图片描述

生成的 SQL:

SELECT t.id,t.name,t.id AS userId,t.name AS name,t2.id,t2.role_name,t2.id AS roleId,t2.role_name AS roleName FROM user t INNER JOIN user_role_mapping t1 ON (t1.user_id = t.id) INNER JOIN role t2 ON (t2.id = t1.role_id) WHERE t.delete_flag='0' AND t2.delete_flag='0'

或者通过写简单SQL的方式调用,如:

@Slf4j
@SpringBootTest
class MybatisPlusJoinApplicationTests {@ResourceUserService userService;// 查询用户和角色信息@Testvoid contextLoads() {List<UserRoleVO> userRoleVOS = userService.selectJoinList(UserRoleVO.class,new MPJQueryWrapper<User>().setAlias("u").select("u.id AS userId","u.name").innerJoin("user_role_mapping m ON u.id = m.user_id").innerJoin("role r ON m.role_id = r.id").select("r.id AS roleId","r.role_name"));userRoleVOS.forEach(vo-> log.info(vo.toString()));}}

运行结果:

在这里插入图片描述
生成的SQL

SELECT u.id AS userId,u.name,r.id AS roleId,r.role_name FROM user u INNER JOIN user_role_mapping m ON u.id = m.user_id INNER JOIN role r ON m.role_id = r.id WHERE u.delete_flag='0'

例如:查看 admin 角色下的用户信息:

@Slf4j
@SpringBootTest
class MybatisPlusJoinApplicationTests {@ResourceUserService userService;// 查看 `admin` 角色下的用户信息@Testvoid findAdamUsers() {List<User> users = userService.selectJoinList(User.class,new MPJLambdaWrapper<User>().selectAll(User.class).innerJoin(UserRoleMapping.class, UserRoleMapping::getUserId, User::getId).innerJoin(Role.class, Role::getId, UserRoleMapping::getRoleId).eq(Role::getRoleName, "admin"));users.forEach(u -> log.info(u.toString()));}}

运行结果:

在这里插入图片描述
生成的SQL

SELECT t.id,t.name,t.age,t.email,t.username,t.password,t.status,t.delete_flag FROM user t INNER JOIN user_role_mapping t1 ON (t1.user_id = t.id) INNER JOIN role t2 ON (t2.id = t1.role_id) WHERE t.delete_flag='0' AND t2.delete_flag='0' AND (t2.role_name = ?)

例如:查看和小明同角色的用户信息,需要两次关联 user 表:

@Slf4j
@SpringBootTest
class MybatisPlusJoinApplicationTests {@ResourceUserService userService;// 查看和`小明`同角色的用户信息@Testvoid findUsers() {List<User> users = userService.selectJoinList(User.class,new MPJLambdaWrapper<User>().innerJoin(UserRoleMapping.class, "m1", UserRoleMapping::getUserId, User::getId).innerJoin(UserRoleMapping.class, "m2", UserRoleMapping::getRoleId, UserRoleMapping::getRoleId).innerJoin(User.class, "u2", User::getId, UserRoleMapping::getUserId).eq("t.name", "小明").ne("u2.name","小明").selectAll(User.class,"u2"));users.forEach(u -> log.info(u.toString()));}}

运行结果:

在这里插入图片描述
生成的SQL

SELECT u2.id,u2.name,u2.age,u2.email,u2.username,u2.password,u2.status,u2.delete_flag FROM user t INNER JOIN user_role_mapping m1 ON (m1.user_id = t.id) INNER JOIN user_role_mapping m2 ON (m2.role_id = m1.role_id) INNER JOIN user u2 ON (u2.id = m2.user_id) WHERE t.delete_flag='0' AND u2.delete_flag='0' AND (t.name = ? AND u2.name <> ?)

或者使用 SQL的写法:

@Slf4j
@SpringBootTest
class MybatisPlusJoinApplicationTests {@ResourceUserService userService;// 查看和`小明`同角色的用户信息@Testvoid findUsers() {List<User> users = userService.selectJoinList(User.class,new MPJQueryWrapper<User>().setAlias("u1").innerJoin("user_role_mapping m1 ON u1.id = m1.user_id").innerJoin("user_role_mapping m2 ON m1.role_id = m2.role_id").innerJoin("user u2 ON m2.user_id = u2.id").eq("u1.name", "小明").ne("u2.name","小明").selectAll(User.class, "u2"));users.forEach(u -> log.info(u.toString()));}}

运行后可以得到相同的结果。

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

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

相关文章

OpenCV 画极线

from pylab import * import cv2from backend._gs_ import stereo_cameradef compute_epipole(F):""" 从基础矩阵 F 中计算右极点(可以使用 F.T 获得左极点)"""# 返回 F 的零空间(Fx0)U,S,V np.linalg.svd(F)e V[-1]return e/e[2]def plot_epi…

故障诊断模型 | Maltab实现BiLSTM双向长短期记忆神经网络故障诊断

文章目录 效果一览文章概述模型描述源码设计参考资料效果一览 文章概述 故障诊断模型 | Maltab实现BiLSTM双向长短期记忆神经网络故障诊断 模型描述 利用各种检查和测试方法,发现系统和设备是否存在故障的过程是故障检测;而进一步确定故障所在大致部位的过程是故障定位。故障…

RK3588编译MXNet框架

目录 1. 背景 2.编译MXNet准备 3.开发板编译 1. 背景 MXNet&#xff08;也称为Apache MXNet或incubator-mxnet&#xff09;是一个开源的深度学习框架&#xff0c;它最初由华为和亚马逊AWS共同开发&#xff0c;并于2017年成为Apache软件基金会的孵化项目。MXNet旨在提供高效、…

【ArcGIS】CSV表导入Arcgis时字段类型改变

一个小记录&#xff1a; 可以看见我的文件夹里不知道我怎么操作的&#xff0c;多出了一个【ini】结尾的文件。 里面显示&#xff0c;我的文件里对应的几列限定为text 这也是为什么我进行xy表转point操作时无法进行的原因 不管我怎么在 csv操作&#xff0c;修改列的单元格格式都…

oracle,CLOB转XML内存不足,ORA-27163: out of memory ORA-06512: at “SYS.XMLTYPE“,

通过kettle采集数据时&#xff0c;表输入的组件&#xff0c;查询报错。 ORA-27163: out of memory ORA-06512: at “SYS.XMLTYPE”, line 272 ORA-06512: at line 1 通过 ALTER SESSION SET EVENTS ‘31156 trace name context forever, level 0x400’; 修改会话配置 或直接修改…

数据结构学习笔记——链式表示中的双链表及循环单/双链表

一、双链表 &#xff08;一&#xff09;双链表的定义 双链表是在单链表结点上增添了一个指针域prior&#xff0c;指针域prior指向当前结点的前驱结点&#xff0c;即此时链表的每个结点中都有两个指针域prior和next&#xff0c;从而可以很容易通过后继结点找到前驱结点&#x…

视阅口译有何特点,哪里提供视阅口译翻译?

据了解&#xff0c;视阅口译是一种涉及视听和口头表达的翻译方式&#xff0c;它在跨文化交流等领域中起到了非常重要的作用。那么&#xff0c;视阅口译有何特点&#xff0c;哪里提供专业的视阅口译服务&#xff1f; 我们知道&#xff0c;视阅口译就是基于事先准备好的讲稿或文…

【HMS Core】机器学习服务热门问题合集

【关键词】 机器学习服务、文本识别、身份证识别 【问题描述1】 机器学习服务的文本识别能力&#xff0c;是否支持草书等&#xff1f; 【解决方案】 草书是不支持的&#xff0c;目前建议使用较为规范的字体测试。 【问题描述2】 机器学习服务是否支持训练模型&#xff1f;…

Docker 运行swagger-editor实现在线接口文档维护与调试

文章目录 一、序二&#xff0c; Docker部署准备1. 编辑docker-compose.yml2. 新增启动、停止脚本3. 样例 swagger.yaml 三&#xff0c; 启动swagger-editor1. 使用说明2. 完整代码备份 一、序 因工作需要&#xff0c;需要搭建python运行环境&#xff0c;项目中python基于flask…

spark

spark Spark可以将Hadoop集群中的应用在内存中的运行速度提升100倍&#xff0c;甚至能够将应用在磁盘上的运行速度提升10倍。除了Map和Reduce操作之外&#xff0c;Spark还支持SQL查询&#xff0c;流数据&#xff0c;机器学习和图表数据处理。开发者可以在一个数据管道用例中单独…

华锐技术何志东:证券核心交易系统分布式改造将迎来规模化落地阶段

近年来&#xff0c;数字化转型成为证券业发展的下一战略高地&#xff0c;根据 2021 年证券业协会专项调查结果显示&#xff0c;71% 的券商将数字化转型列为公司战略任务。 在落地数字化转型战略过程中&#xff0c;证券业核心交易系统面临着不少挑战。构建新一代分布式核心交易…

SpringMVC Day 06 : 转发视图

前言 在SpringMVC框架中&#xff0c;视图解析器可以将逻辑视图名称转换为实际的视图对象。除了直接渲染视图&#xff0c;你还可以通过SpringMVC提供的转发和重定向机制来跳转到另一个视图。在本篇博客中&#xff0c;我们将学习SpringMVC中的转发视图技术&#xff0c;以及如何使…

Android 10适配外部存储方案

Android Api 29 对文件和文件夹进行了重大更改。不允许使用外部存储&#xff0c;如下方法&#xff1a; Environment.getExternalStorageDirectory() /mnt/sdcard Environment.getExternalStoragePublicDirectory(“test”) /mnt/sdcard/test 只能使用内部存储 getExterna…

抖音小店怎么做?五步教你做好抖店,新手快来看!

我是电商珠珠 新手在做抖音小店的时候&#xff0c;往往在入驻完成之后&#xff0c;就不知道后续应该怎么操作了。 我将抖店的运营分为了五个步骤&#xff0c;可以供大家参考。 一、类目 开店之前选择好的类目&#xff0c;后续如果想要更改的话可以随时更改。 不过需要下架…

python函数的定义与调用

python定义函数和函数的使用 函数 函数是对程序逻辑进行结构化或过程化的一种编程方法&#xff0c;将整块代码巧妙地隔离成易于管理的小块。把重复代码放到函数中而不是进行大量的拷贝&#xff0c;这样既能节省空间&#xff0c;也有助于保持一致性&#xff1b;通常函数都是用…

metaRTC集成flutter ui demo编译指南

概要 Flutter是由Google开发的开源UI工具包&#xff0c;用于构建跨平台应用程序&#xff0c;支持linux/windows/mac/android/ios等操作系统。 metaRTC新增flutter demo&#xff0c;支持linux/windows/mac/android/ios操作系统&#xff0c;此demo在ubuntu桌面环境下测试成功。…

【文献分享】基于线特征的激光雷达和相机外参自动标定

论文题目&#xff1a;Line-based Automatic Extrinsic Calibration of LiDAR and Camera 中文题目&#xff1a;基于线特征的激光雷达和相机外参自动标定 作者&#xff1a;Xinyu Zhang, Shifan Zhu, Shichun Guo, Jun Li, and Huaping Liu 作者机构&#xff1a;清华大学汽车安…

SAML- 安全断言标记语言

一、概念 安全断言标记语言&#xff08;SAML&#xff09;是一种开放标准&#xff0c;用于在各方之间&#xff08;特别是身份提供商和服务提供商之间&#xff09;交换身份验证和授权数据。SAML 是一种基于XML的安全断言标记语言&#xff08;服务提供商用来做出访问控制决策的语句…

Unity 多图片(带透明通道)合成

取个巧&#xff0c;利用Camera和Render Texture 多个2d图片组合成型 每个Square都单独设置一个层级 相机设置 RenderTexture设置&#xff0c;然后将RenderTexture放在一个RawImage上 以下是生成图片的代码 using UnityEngine.UI; using System.Collections; using System.…

【zTree】节点添加不同操作按钮,点击后生成弹窗

zTree api 文档&#xff1a;https://www.treejs.cn/v3/api.php 1. 初始化树的配置项 const initZtreeSetting () > {const setting {view: {addHoverDom: addHoverDom, // 显示用户自定义控件selectedMulti: false,// 是否允许同时选中多个节点&#xff0c;默认为truesh…