当前位置:   article > 正文

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

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

写入测试数据

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

下面新建 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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

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

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

下面通过 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;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

关联查询

@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()));
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

运行结果:

在这里插入图片描述

生成的 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'
  • 1

或者通过写简单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()));
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

运行结果:

在这里插入图片描述
生成的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'
  • 1

例如:查看 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()));
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

运行结果:

在这里插入图片描述
生成的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 = ?)
  • 1

例如:查看和小明同角色的用户信息,需要两次关联 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()));
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

运行结果:

在这里插入图片描述
生成的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 <> ?)
  • 1

或者使用 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()));
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/830429
推荐阅读
相关标签
  

闽ICP备14008679号