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

news2024/11/20 20:32:07

一、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: 8010

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.bxc.mybatisplusjoin.domain.entity
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  global-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 默认true
  banner: 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 {

    @Resource
    UserService userService;

    // 查询用户和角色信息
    @Test
    void 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 {

    @Resource
    UserService userService;

    // 查询用户和角色信息
    @Test
    void 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 {

    @Resource
    UserService userService;

    // 查看 `admin` 角色下的用户信息
    @Test
    void 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 {

    @Resource
    UserService userService;

    // 查看和`小明`同角色的用户信息
    @Test
    void 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 {

    @Resource
    UserService userService;

    // 查看和`小明`同角色的用户信息
    @Test
    void 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.coloradmin.cn/o/1154705.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

致远OA wpsAssistServlet任意文件上传漏洞复现 [附POC]

文章目录 致远OA wpsAssistServlet任意文件上传漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 致远OA wpsAssistServlet任意文件上传漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用…

突破时空局限:数字调度系统引领煤炭行业新纪元

随着社会经济的发展&#xff0c;能源需求不断增加&#xff0c;煤炭作为重要的能源资源&#xff0c;在全球能源结构中扮演着重要角色。然而&#xff0c;煤炭行业面临着许多挑战&#xff0c;包括资源开采的不可回复性、环境污染问题以及安全生产隐患等。在这样的背景下&#xff0…

Android Groovy 迁移到 KTS

文章目录 Groovy 迁移到 KTS概述迁移流程setting.gradleproject/build.gradlemodule/build.gradle处理ext扩展函数依次创建如下目录和文件使用 源码 Groovy 迁移到 KTS 概述 Android Studio是使用Gradle来编译&#xff0c;而默认的构建语言是Groovy&#xff0c;但是Gradle实际…

竞赛选题 深度学习图像风格迁移

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

你真的会学习网络安全吗?

我敢说&#xff0c;现在网上90%的文章都没有把网络安全该学的东西讲清楚。 为什么&#xff1f;因为全网更多的都是在讲如何去渗透和公鸡&#xff0c;却没有把网安最注重的防御讲明白。 老话说得好&#xff1a;“攻击&#xff0c;是为了更好的防御。”如果连初衷都忘了&#xff…

Grafana 图表 Table 根据 Key 修改背景颜色

文章目录 前言1. 配置过程1.1 创建 override1.2 Add override property1.3 Value mappings 2. 效果展示 前言 需要配置一个备份任务的 Dashboard 展示备份的状态&#xff0c;如果备份状态是 Completed 表示正常&#xff08;绿色背景&#xff09;&#xff0c;如果是 Error 表示…

LOGO设计工具都有哪些?分享这6款

如果一个品牌想要脱颖而出&#xff0c;它必须有一个令人印象深刻的品牌标志。创建一个专业的标志&#xff0c;设计师不能简单地用刷子手绘&#xff0c;必须使用专业的标志设计软件来制作。 市场上有各种各样的标志设计软件&#xff1a;桌面、在线应用、免费&#xff0c;甚至人…

Kubernetes深度剖析,从基础到高级,带你领略K8s的魅力

一、Kubernetes 是 Google 团队发起并维护的基于 Docker 的开源容器集群管理系统&#xff0c;它不仅支持常见的云平台&#xff0c;而且支持内部数据中心。 建于 Docker 之上的 Kubernetes 可以构建一个容器的调度服务&#xff0c;其目的是让用户透过 Kubernetes 集群来进行云端…

星环科技分布式向量数据库Transwarp Hippo正式发布,拓展大语言模型时间和空间维度

随着企业、机构中非结构化数据应用的日益增多以及AI的爆发式增长所带来的大量生成式数据&#xff0c;所涉及的数据呈现了体量大、格式和存储方式多样、处理速度要求高、潜在价值大等特点。但传统数据平台对这些数据的处理能力较为有限&#xff0c;如使用文件系统、多类不同数据…

0002net程序设计-net家电维修保养信息系统

文章目录 **摘要**目录系统设计开发环境 摘要 家电维修保养信息系统提供给用户一个家电信息管理的网站&#xff0c;最新的家电信息让用户及时了解维修知识,保养方式的同时,还能通过交流区互动更方便。本系统采用了B/S体系的结构&#xff0c;使用了net技术以及SQL SERVER作为后…

uniapp 关于 video 组件的缩放比例问题

在 container 样式的 padding-bottom 设置比例值 9/16 比例值&#xff1a;56.25% 3/4 比例值&#xff1a;75% <view class"container"><video class"video-box" src"xxx.mp4" /> </view> .container {position: relative;wid…

【STL】:list用法详解

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关list的使用&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结构…

SQL注入思路扩展

目录 一、资产搜集 二、开始sql注入常规流程 三、sqlmap验证 总结&#xff1a;测试sql注入的时候不要只局限于明文传输&#xff0c;也要注意编码或者加密后的值。 还没看够&#xff1f;欢迎关注&#xff0c;带你走进黑客世界&#xff0c;下面也有免费的靶场视频 一、资产搜…

HCIA --- 综合实验(结束)

一、实验拓扑及要求 二、整体IP规划 三、解决方案 四、解决步骤配置命令 一、基本部分 一、交换机 1、创建对应VLAN&#xff0c;对应接口划入对应VLAN中&#xff0c;创建Trunk干道&#xff0c;配置HTTP服务器IP LSW1 [sw1]vlan batch 2 to 3 [sw1]interface e0/0/1 [sw1-E…

idea提交代码一直提示 log into gitee

解决idea提交代码一直提示 log into gitee问题 文章目录 打开setting->Version control->gitee,删除旧账号&#xff0c;重新配置账号&#xff0c;删除重新登录就好 打开setting->Version control->gitee,删除旧账号&#xff0c;重新配置账号&#xff0c;删除重新登…

部署前端项目到宝塔面板(腾讯阿里服务器均适用)

写在前面&#xff0c;本网站部署的是前端nuxt.js项目&#xff0c;后端部分在本人的其他博文&#xff0c;请移步 【起步】服务器端 打开自己的轻量服务器的管理面板 确保服务器已经打开&#xff0c;如下图所示 来到域名列表&#xff0c;解析域名&#xff0c;如下图所示 的…

[转载]C++序列化框架介绍和对比

Google Protocol Buffers Protocol buffers 是一种语言中立&#xff0c;平台无关&#xff0c;可扩展的序列化数据的格式&#xff0c;可用于通信协议&#xff0c;数据存储等。 Protocol buffers 在序列化数据方面&#xff0c;它是灵活的&#xff0c;高效的。相比于 XML 来说&…

怎么理解电流超前电压、电压超前电流?

电容和电感&#xff0c;电压超前电流&#xff0c;电流超前电压都是我们经常听到的。作为非专业人士&#xff0c;这些听起来确实有点摸不着头脑&#xff0c;今天特别查了下电容、电感、电压电流相关资料&#xff0c;总算是弄明白了&#xff0c;在此特地记录下&#xff01; 1. 电…

打造企业级门户,WorkPlus助您打造个性化与高效的企业通讯平台

在现代企业运营中&#xff0c;良好的内部沟通与信息管理至关重要。为满足企业对于高效沟通与信息发布的需求&#xff0c;WorkPlus推出了企业门户APP&#xff0c;为企业提供全新的信息管理与沟通协作体验。 作为一站式企业门户&#xff0c;WorkPlus连接了组织、员工和信息的纽带…

GitLab(2)——Docker方式安装Gitlab

目录 一、前言 二、安装Gitlab 1. 搜索gitlab-ce镜像 2. 下载镜像 3. 查看镜像 4. 提前创建挂载数据卷 5. 运行镜像 三、配置Gitlab文件 1. 配置容器中的/etc/gitlab/gitlab.rb文件 2. 重启容器 3. 登录Gitalb ① 查看初始root用户的密码 ② 访问gitlab地址&#…