如何在MyBatis Plus中实现多表联合查询并分页?

在MyBatis Plus中实现多表联合查询并分页,主要有两种核心思路:一种是使用自定义SQL(XML或注解)配合MyBatis Plus的分页对象,另一种是借助第三方扩展库如 mybatis-plus-join。下面的表格详细对比了这两种主流方案及其实现要点,可以帮助你快速选择。

实现方案核心思路优点适用场景
自定义SQL在Mapper的XML文件或@Select注解中编写完整的联表SQL,方法参数和返回值使用MyBatis Plus的IPage对象。灵活性极高,可以编写任意复杂的SQL语句;性能可控性好。中、高度复杂的多表关联查询,需要精细控制SQL逻辑的场景。
mybatis-plus-join扩展库Mapper继承MPJBaseMapper,使用专用的MPJLambdaWrapperMPJQueryWrapper构建关联查询和分页。开发效率高,能用Lambda表达式和链式调用,写法与单表查询类似,类型安全。关联关系清晰、复杂度中等的查询,追求快速开发和代码简洁性的场景。

💡 方案一:自定义SQL实现联表分页

这是最常用且基础的方式,其工作流程可以概括为:在Service层准备分页信息,在Mapper层通过自定义SQL执行查询,最后由MyBatis Plus的分页插件自动处理分页参数和结果。

1. 实现步骤与代码示例

  • Service层:创建分页对象并调用Mapper方法。
@Service
public class UserServiceImpl {
    @Autowired
    private UserMapper userMapper;
    
    public IPage<UserOrderDTO> getUserOrdersPage(Page<UserOrderDTO> page, Long userId) {
        // 将分页对象和查询条件传递给Mapper方法
        return userMapper.selectUserOrdersPage(page, userId);
    }
}
  • Mapper接口:方法的第一个参数和返回值均为MyBatis Plus的分页类型。
public interface UserMapper extends BaseMapper<User> {
    // 定义分页查询方法
    IPage<UserOrderDTO> selectUserOrdersPage(IPage<UserOrderDTO> page, @Param("userId") Long userId);
}
  • Mapper XML:编写联表SQL,无需在SQL中书写LIMIT等分页关键字,分页插件会自动处理。
<select id="selectUserOrdersPage" resultType="com.example.dto.UserOrderDTO">
    SELECT 
        u.id AS userId, 
        u.name AS userName, 
        o.product_name AS productName
    FROM 
        user u
    LEFT JOIN 
        order o ON u.id = o.user_id
    WHERE 
        u.id = #{userId}
    <!-- 分页插件会自动在此SQL基础上添加分页逻辑 -->
</select>

2. 使用QueryWrapper传递动态条件

如果你的查询条件需要动态构建,可以将QueryWrapper作为参数传到XML中。

  • Mapper接口
IPage<UserOrderDTO> selectUserOrdersPage(IPage<UserOrderDTO> page, @Param("ew") Wrapper<UserOrderDTO> wrapper);
  • Mapper XML:在SQL中使用 ${ew.customSqlSegment}来插入Wrapper生成的条件。
<select id="selectUserOrdersPage" resultType="com.example.dto.UserOrderDTO">
    SELECT ... FROM ...
    WHERE 1=1
    ${ew.customSqlSegment} <!-- Wrapper生成的条件(如 eq, like)会在这里填充 -->
</select>

🚀 方案二:使用mybatis-plus-join扩展库

这个第三方库为MyBatis Plus提供了类似单表查询的联表操作体验。

1. 引入依赖

首先需要在项目中添加依赖。

<dependency>
    <groupId>com.github.yulichang</groupId>
    <artifactId>mybatis-plus-join</artifactId>
    <version>1.2.4</version> <!-- 请使用最新版本 -->
</dependency>

2. 代码示例

  • Mapper接口继承MPJBaseMapper
public interface UserMapper extends MPJBaseMapper<User> {
}
  • 使用MPJLambdaWrapper进行类型安全的联表分页查询。
@Autowired
private UserMapper userMapper;

public IPage<UserOrderDTO> selectJoinPage() {
    MPJLambdaWrapper<User> wrapper = new MPJLambdaWrapper<User>()
            .selectAll(User.class) // 查询User表所有字段
            .select(Order::getProductName) // 查询Order表的指定字段
            .leftJoin(Order.class, Order::getUserId, User::getId) // 左关联
            .eq(User::getStatus, 1); // 条件

    return userMapper.selectJoinPage(new Page<>(1, 10), UserOrderDTO.class, wrapper);
}

⚠️ 重要前提配置

无论选择哪种方案,都必须确保MyBatis Plus的分页插件已正确配置,否则分页功能不会生效。

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); 
        return interceptor;
    }
}

💎 如何选择?

  • 面对复杂、定制化要求高的联表查询(例如涉及多个分组、聚合函数、子查询或数据库特定语法),自定义SQL方案是更可靠的选择。
  • 对于关联关系简单明了的常规查询,并且希望代码简洁、易于维护mybatis-plus-join扩展库能极大提升开发效率。

希望这些详细的解释和代码示例能帮助你顺利实现需求。如果你的查询场景有特定的复杂性,比如需要多个LEFT JOIN或者复杂的结果映射,可以分享更多细节,我能提供更具体的建议。


作 者:南烛
链 接:https://www.itnotes.top/archives/1084
来 源:IT笔记
文章版权归作者所有,转载请注明出处!


上一篇
下一篇