MyBatis-Plus 分页失效问题解析:@Param 注解的影响与解决方案

引言

在 Spring Boot + MyBatis-Plus 的开发中,分页查询是常见的需求。

然而,有时我们会遇到分页失效的问题,尤其是在方法参数上添加 @Param 注解后。

本文将通过一个实际案例,分析 @Param 注解如何影响 MyBatis-Plus 的分页机制,并提供解决方案。


问题重现

1. 原始代码

AlertServiceImpl 中,分页查询方法 page() 调用了 AlertDaolist() 方法:

复制代码
@Override
public PageData<AlertDTO> page(Map<String, Object> params) {
    IPage<AlertEntity> page = getPage(params, null, false);
    List<AlertDTO> list = baseDao.list(params);
    return getPageData(list, page.getTotal(), AlertDTO.class);
}

AlertDaolist() 方法如下:

复制代码
@DataSource(name = DataSourceNames.SECOND)
List<AlertDTO> list(@Param("p") Map<String, Object> params);

此时,分页失效,SQL 查询返回所有数据,而不是分页后的结果。

2. 修复后的代码

移除 @Param("p") 后,分页恢复正常:

复制代码
@DataSource(name = DataSourceNames.SECOND)
List<AlertDTO> list(Map<String, Object> params);

原因分析

1. MyBatis-Plus 的分页机制

MyBatis-Plus 的分页插件(PaginationInterceptor)会在执行 SQL 前自动解析分页参数(如 pagesize),并修改 SQL 添加 LIMIT 子句。

2. @Param 注解的影响

  • 不加 @Param:MyBatis-Plus 能直接读取 Map<String, Object> 中的分页参数(如 params.get("page")),并正确分页。
  • @Param("p"):整个 Map 被包装成命名参数 p,MyBatis-Plus 无法直接访问 p.pagep.size,导致分页插件无法识别分页参数,最终 SQL 没有 LIMIT 子句,返回全部数据。

解决方案

方案 1:移除 @Param 注解(推荐)

复制代码
@DataSource(name = DataSourceNames.SECOND)
List<AlertDTO> list(Map<String, Object> params);

优点

  • 保持 MyBatis-Plus 默认分页行为,无需额外修改 SQL。
  • 代码简洁,符合 MyBatis-Plus 最佳实践。

方案 2:手动分页(适用于必须使用 @Param 的情况)

如果必须使用 @Param,可以在 XML 中手动添加 LIMIT

复制代码
<select id="list" resultType="io.installer.modules.sys.dto.AlertDTO">
    SELECT ...
    <where>
        hd.is_deleted=0
    </where>
    LIMIT #{p.page}, #{p.size}
</select>

缺点

  • 需要手动计算分页偏移量,容易出错。
  • 不适用于所有数据库(如 Oracle 需要使用 ROWNUM)。

方案 3:改用 IPage 参数(最佳 MyBatis-Plus 实践)

复制代码
@DataSource(name = DataSourceNames.SECOND)
List<AlertDTO> list(IPage<AlertDTO> page, @Param("query") Map<String, Object> params);

优点

  • MyBatis-Plus 自动处理分页逻辑,无需手动干预。
  • 支持更灵活的分页查询。

总结

|---------------|-------------|----------------------|----------|
| 方案 | 适用场景 | 优点 | 缺点 |
| 移除 @Param | 一般情况 | 简单高效 | 无法自定义参数名 |
| 手动分页 | 必须使用 @Param | 可控性强 | 需要手动计算分页 |
| IPage 参数 | 复杂分页查询 | 符合 MyBatis-Plus 最佳实践 | 需要调整方法签名 |

最佳实践 建议

  • 优先移除 @Param**,让 MyBatis-Plus 自动处理分页。
  • 如需自定义参数名,可改用 IPage 参数 + @Param 组合。

结论

在 MyBatis-Plus 中,@Param 注解有时会干扰分页插件的参数解析机制,导致分页失效。通过移除 @Param 或改用 IPage 参数,可以确保分页功能正常工作。理解 MyBatis-Plus 的分页机制,有助于避免类似问题,提高开发效率。