mybatis plus join(建议收藏)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言

在现代企业级应用开发中,数据库表之间的关联查询是高频需求。MyBatis Plus 作为简化 MyBatis 开发的工具包,通过内置的 JOIN 语法和链式调用,让多表查询变得直观高效。本文将从基础概念到实战案例,系统讲解如何利用 MyBatis Plus Join 实现多表关联查询,并结合具体场景分析其优势与注意事项。无论是刚接触数据库关联查询的新手,还是希望提升开发效率的中级开发者,都能从中获得实用技巧。


核心概念解析

什么是 MyBatis Plus Join?

MyBatis Plus Join 是 MyBatis-Plus 提供的多表查询功能模块,通过 leftJoin()rightJoin()innerJoin() 等方法,结合 on() 条件表达式,将传统 MyBatis 的 XML 配置简化为代码层面的链式调用。

对比传统 MyBatis 的优势

传统方式MyBatis Plus Join
需编写 XML 文件定义 SQL 语句通过代码直接构建查询逻辑
语法复杂度高,维护成本高链式调用直观,学习成本低
缺乏类型安全,容易出错通过代码校验减少语法错误

比喻:如果将传统 SQL 比作手工搭建积木,那么 MyBatis Plus Join 就是提供了预装的积木模板,开发者只需按逻辑拼接即可快速完成复杂结构。


基础用法与示例

1. 环境准备

假设存在两个表:user(用户表)和 order(订单表),字段如下:

-- user表
CREATE TABLE `user` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `name` VARCHAR(50) NOT NULL,
  `age` INT
);

-- order表
CREATE TABLE `order` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT,
  `user_id` BIGINT NOT NULL,
  `amount` DECIMAL(10,2) NOT NULL
);

2. 单表查询与 JOIN 对比

单表查询代码示例

// 查询用户信息
List<User> users = userMapper.selectList(null);

使用 JOIN 实现用户与订单关联

List<Order> orders = orderMapper.selectJoinList(new LambdaQueryWrapper<Order>()
    .leftJoin(User.class, "user") // 关联user表,别名设为user
    .on(Order::getUserId, User::getId) // 关联条件:order.user_id = user.id
    .select(Order::getId, Order::getAmount, User::getName) // 选择字段
);

3. 常见 JOIN 类型

  • INNER JOIN:返回两个表关联条件匹配的记录(默认类型)。
  • LEFT JOIN:保留左表所有记录,即使右表无匹配项。
  • RIGHT JOIN:保留右表所有记录,即使左表无匹配项。

示例代码

// LEFT JOIN 实现查询所有用户及其订单(即使无订单也显示用户信息)
List<User> usersWithOrders = userMapper.selectJoinList(new LambdaQueryWrapper<User>()
    .leftJoin(Order.class, "order")
    .on(User::getId, Order::getUserId)
    .select(User::getName, Order::getAmount)
);

多表关联场景详解

场景一:一对一关联

需求:查询用户及其最新一条订单信息。

实现思路

  1. 通过 INNER JOIN 关联 userorder 表。
  2. 使用 groupBy()max() 聚合函数筛选最新订单。

代码示例

List<User> users = userMapper.selectJoinList(new LambdaQueryWrapper<User>()
    .innerJoin(Order.class, "order")
    .on(User::getId, Order::getUserId)
    .groupBy(User::getId) // 按用户分组
    .apply("order.id = (SELECT MAX(id) FROM `order` WHERE user_id = user.id)") // 子查询获取最新订单ID
);

场景二:一对多关联

需求:查询用户及其所有订单,并按订单金额排序。

实现代码

List<User> users = userMapper.selectJoinList(new LambdaQueryWrapper<User>()
    .leftJoin(Order.class, "order")
    .on(User::getId, Order::getUserId)
    .orderByDesc(Order::getAmount) // 按金额降序
);

场景三:多对多关联

假设存在 userroleuser_role(中间表)三个表,查询用户及其角色名称:

关联代码

List<User> users = userMapper.selectJoinList(new LambdaQueryWrapper<User>()
    .leftJoin(UserRole.class, "user_role")
    .on(User::getId, UserRole::getUserId)
    .leftJoin(Role.class, "role")
    .on(UserRole::getRoleId, Role::getId)
    .select(User::getName, Role::getRoleName)
);

自定义 JOIN 的高级用法

1. 动态条件构建

通过 QueryWrapperand() 方法动态添加条件:

QueryWrapper<Order> wrapper = new QueryWrapper<>();
if (userId != null) {
    wrapper.eq("user_id", userId);
}
List<Order> orders = orderMapper.selectJoinList(wrapper
    .leftJoin(User.class, "user")
    .on("user.id = order.user_id")
);

2. 自定义字段映射

当表字段名与实体类属性名不一致时,可通过 @TableField 注解指定关联字段:

@Data
public class Order {
    @TableField("user_id")
    private Long userId;
}

3. 性能优化技巧

  • **避免 SELECT ***:显式指定需要的字段,减少网络传输开销。
  • 分页处理:结合 Page 对象实现分页查询,避免一次性加载大量数据。

常见问题与解决方案

问题1:关联后字段命名冲突

现象:若 userorder 表均存在 name 字段,查询时会报错。

解决方案:使用 AS 别名重命名字段:

.select("user.name AS user_name", "order.name AS order_name")

问题2:JOIN 后数据重复

原因:多表关联可能因关联条件不严谨导致重复记录。

解决方法

  1. 检查 ON 条件是否唯一约束。
  2. 使用 DISTINCTGROUP BY 去重。

问题3:性能下降

优化建议

  • 添加索引在关联字段(如 user_id)。
  • 使用 EXPLAIN 分析 SQL 执行计划。

结论

通过本文的讲解,开发者可以掌握 MyBatis Plus Join 的核心用法,并通过实际案例理解其在一对一、一对多、多对多场景中的应用。无论是简化代码逻辑,还是提升开发效率,MyBatis Plus Join 都是值得深入学习的工具。未来版本中,MyBatis-Plus 可能进一步扩展对复杂关联查询的支持,开发者需持续关注官方文档更新,以充分利用框架的潜力。

提示:实践是掌握技术的关键!建议读者根据本文案例,结合本地数据库环境进行代码调试,逐步理解 JOIN 的实现机制。

最新发布