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

news/2024/11/26 5:22:33/

一、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.ppmy.cn/news/1192433.html

相关文章

C++11 auto限制

限制&#xff1a; auto 不能用于函数参数auto 不能用于非静态成员变量auto 无法定义数组auto 无法推导出模板参数 推荐一个零声学院项目课&#xff0c;个人觉得老师讲得不错&#xff0c;分享给大家&#xff1a; 零声白金学习卡&#xff08;含基础架构/高性能存储/golang云原生…

Spring@Lazy是如何解决构造函数循环依赖问题

Spring实例化源码解析之循环依赖CircularReference这章的最后我们提了一个构造函数形成的循环依赖问题&#xff0c;本章就是讲解利用Lazy注解如何解决构造函数循环依赖和其原理。 准备工作 首先创建两个构造函数循环依赖的类&#xff0c;TestA和TestB&#xff0c;代码如下&am…

掌握口才与演讲技巧,让你职场中脱颖而出

在职场竞争日趋激烈的今天&#xff0c;口才和演讲能力已经成为一个人成功的重要标志之一。掌握了优秀的口才与演讲技巧&#xff0c;不仅可以帮助你在工作中更好地表达自己和传达信息&#xff0c;同时也可以让你在同事和上级心中留下深刻印象&#xff0c;从而在职场中脱颖而出&a…

坚持#第420天~阿里云轻量服务器内存受AliYunDunMonito影响占用解决方法

阿里云轻量服务器内存受AliYunDunMonito影响占用解决方法&#xff0c;亲测有效&#xff1a; Mobax好卡啊&#xff0c;那就直接在阿里云后台操作即可&#xff0c;阿里云后台也可以上传文件。 Navicat mysql好卡啊&#xff0c;那就直接在阿里云后台最上面帮助的右边有个数据库&…

机器人仿真-gazebo学习笔记(3)URDF和机器人模型

1.URDF简介 URDF(统一机器人麦哦书格式)是ROS中的重要机器人模型描述格式&#xff0c;ROS提供了URDF文件的c解析器&#xff0c;可以解析URDF文件中使用XML格式的机器人模型。 urdf - ROS Wiki 自己查阅ros官方对URDF的介绍其实会强于大部分网上流传的文章。 1.URDF文件常用的…

【UE】从UI拖拽生成物体 —— 更改位置与定点销毁

本篇在上一篇博客&#xff08;【UE】从UI中拖拽生成物体-CSDN博客&#xff09;基础上继续增加更改生成的Actor的位置与定点销毁Actor的功能。 目录 效果 步骤 一、修改生成好的Actor位置 解决问题一&#xff1a;从UI拖出多个actor后&#xff0c;只能对第一个拖出的actor的…

公司老项目springmvc jsp 自定义多数据源 转到springboot 整理

真实完整步骤&#xff0c;踩坑整理 有同样的坑&#xff0c;欢迎补充整理 网上的案例老是少了很多配置&#xff0c;本案例涉及到 spring-mvc&#xff0c;自定义多数据源&#xff0c;统一前缀&#xff0c;事务&#xff0c;mybatis&#xff0c;jsp访问异常&#xff0c;静态文件。…

正则表达式续篇

位置锚定&#xff1a; ^:行首锚定&#xff0c;表示以什么为开头 例如&#xff1a; $:行尾锚定&#xff0c;表示以什么为结尾 例如&#xff1a; ^&#xff1a;匹配的是空行 例如&#xff1a; ^root$&#xff1a;匹配整行&#xff0c;而且整行只能有这一个字符串 实验&#x…