使用Mybatis-plus分页查询的Total与实际条数不对应

Mybatis-Plus分页查询优化问题与解决方案
文章讨论了在使用Mybatis-Plus进行多表关联查询时,由于自动优化导致的查询SQL不一致问题。解决方法是关闭分页查询的优化功能。作者提供了关闭`optimizeCountSql`的代码示例。

现象

对于单表查询是没有问题的。而需要多表关联查询(自写sql)时,就会查询调用Mybatis-Plus的.page(Page page,Wrapper queryWrapper);

可以看到后台实际执行sql有两个。
一个是查询sql的数据:

select
        visit.id as id,
        visit.rfid_card_num as rfidCardNum,
        cp.id as bizClinicalPathId,
        users.nickname as nickName
        from  ecqm_biz_patient_visit visit
        left join ecqm_biz_clinical_path  cp 
         	on  visit.id = cp.pv_id and cp.deleted  = 0
        left join system_users users 
        	on users.id = visit.creator and users.deleted = 0
        WHERE visit .deleted = 0

另一个为统计Total数量的sql;
但是查询total的语句却是:

select count(*) from  ecqm_biz_patient_visit visit 
where visit .deleted = 0

显然是有问题的;

原因

这是因为对查询进行了优化(只查主表符合查询条件的总条数),这就导致两条查询sql的表数量不一致,从而导致查询总条数不一致的情况。

com.baomidou.mybatisplus.extension.plugins.pagination.Page源码:

    /**
     * 自动优化 COUNT SQL
     */
    protected boolean optimizeCountSql = true;
    /**
     * 是否进行 count 查询
     */
    protected boolean searchCount = true;
	
	......其他源码省略
	
	public Page<T> setOptimizeCountSql(boolean optimizeCountSql) {
        this.optimizeCountSql = optimizeCountSql;
        return this;
    }

解决方案

关闭分页查询优化即可: page.setOptimizeCountSql(false)。

Page<BizPatientVisitRespVO> page = new Page<>(pageReqVO.getPageNo(),pageReqVO.getPageSize());
//关闭分页查询优化
page.setOptimizeCountSql(false);
Page<VO> result = bizPatientVisitMapper.getInPatient(page,pageReqVO );
return new PageResult<>(result.getRecords(), result.getTotal());
<think>我们正在解决MyBatis-Plus分页查询只返回总条数而没有具体数据的问题。根据引用内容,常见原因包括页插件未配置、配置正确或未使用MyBatis-Plus页方法。下面将逐步析原因并提供解决方案。###原因析1. **页插件未配置**:MyBatis-Plus页功能依赖于页插件(`PaginationInnerInterceptor`),如果没有在配置类中注册该插件,分页查询会生效,导致返回所有数据或只返回总条数。2.**页配置正确**:即使配置了页插件,如果配置方式错误(例如未将插件添加到MyBatis的拦截器链中),也会导致页失效。 3. **未使用MyBatis-Plus页方法**:如果直接使用MyBatis原生的方法或自定义SQL查询而没有使用MyBatis-Plus提供的页方法(如`selectPage`),则页插件会拦截并处理页逻辑。 ###解决方案####1.确保正确配置页插件在Spring Boot的配置类(通常是带有`@Configuration`注解的类)中,添加页插件: ```java@Configurationpublicclass MybatisPlusConfig{@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptorinterceptor= newMybatisPlusInterceptor();//添加页插件interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL)); //根据数据库类型调整return interceptor;}} ```注意:`DbType`需要根据实际使用的数据库类型设置(如MySQL、Oracle等)。####2.检查分页查询的代码确保在查询时使用MyBatis-Plus提供的页方法,例如:```java//创建页对象,参数为当前页和每页记录数Page<User> page= newPage<>(1,10);//使用QueryWrapper构建查询条件QueryWrapper<User> queryWrapper =new QueryWrapper<>();queryWrapper.eq("status",1); //调用selectPage方法userMapper.selectPage(page, queryWrapper);```此时,`page.getRecords()`会返回当前页的数据列表,`page.getTotal()`返回总记录数。####3.检查自定义SQL的页写法如果使用自定义SQL(在Mapper.xml中写SQL语句),需要确保SQL语句正确且参数传递正确。在Mapper接口中,方法参数必须包含`Page`对象,且返回类型为`Page`: ```java// Mapper接口方法Page<User>selectUserPage(Page<User> page, @Param("state") Integerstate);``` 在XML中,需要手动写`LIMIT`子句,页插件会自动处理:```xml<select id="selectUserPage" resultType="User">SELECT* FROMuser WHEREstate =#{state} </select>``` ####4.检查是否启用了合理化查询引用[2]提到,页插件有一个`reasonable`属性(合理化查询),用于防止查询超出总页数的页码。但这是导致只返回总条数的原因,主要关注点还是插件的配置和使用方法。 ###常见错误排查- **错误1**:忘记在配置类中添加页插件。 -**错误2**:在查询时没有使用`Page`对象作为参数,而是直接使用了`QueryWrapper`,导致页未被触发。- **错误3**:自定义SQL中,Mapper接口的方法参数没有传入`Page`对象,或者返回类型是`Page`。 ###总结当MyBatis-Plus分页查询只返回总条数而没有数据时,请按以下步骤检查:1.确认已正确配置页插件(`PaginationInnerInterceptor`)。 2.确认查询代码使用了`selectPage`方法或Mapper接口中返回`Page`的方法。3.对于自定义SQL,确保Mapper方法的第一个参数是`Page`类型,并且SQL中要写页语句(如`LIMIT`)。如果按照以上步骤操作,分页查询应该能正常返回当前页的数据。如果问题仍然存在,请检查日志输出,看是否有异常信息,并确认数据库连接和SQL语句的正确性。§§相关问题§§1.MyBatis-Plus页插件支持哪些数据库? 2.如何优化MyBatis-Plus分页查询的性能?3.在使用MyBatis-Plus页时,如何处理多表关联查询的页?</think>### MyBatis-Plus 分页查询只返回总条数没有数据的原因及解决方案 #### 原因析 1. **页插件未正确配置**(最常见原因) 未在 MyBatis 配置中注册页拦截器,导致页逻辑未生效[^1]。表现为: ```java Page<User> page = new Page<>(1, 10); userMapper.selectPage(page, null); // page.getRecords() 返回所有数据而非页数据 ``` 2. **自定义SQL未遵循规范** 在 XML 或注解中编写自定义 SQL 时: -使用 `${ew.customSqlSegment}` 拼接条件 - 手动添加了 `LIMIT` 语句导致冲突 - 返回类型页对象匹配 3. **页参数传递错误** - 未将 `Page` 对象作为方法**第一个参数** - 在 Service 层未调用正确的页方法(如误用 `list()` 代替 `page()`) 4. **数据库方言匹配** 页插件未正确配置数据库类型(如 MySQL 配置成 Oracle 方言): ```java // 错误配置示例 new PaginationInnerInterceptor(DbType.ORACLE); // 实际使用 MySQL ``` #### 解决方案 ##### 1. 正确配置页插件(关键步骤) ```java @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加页插件并指定数据库类型 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } ``` ##### 2. 规范自定义 SQL 写法 **Mapper 接口:** ```java @Select("SELECT * FROM user ${ew.customSqlSegment}") Page<User> selectUserPage(Page<User> page, @Param(Constants.WRAPPER) Wrapper<User> wrapper); ``` **XML 配置:** ```xml <select id="selectUserPage" resultType="User"> SELECT id, name FROM user ${ew.customSqlSegment} <!-- 自动拼接页语句 --> </select> ``` ##### 3. 正确调用页方法 **Service 层调用:** ```java // 正确姿势:Page 对象作为第一个参数 Page<User> page = new Page<>(current, size); QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("status", 1); userService.page(page, wrapper); // 使用IService的页方法 List<User> records = page.getRecords(); // 获取当前页数据 long total = page.getTotal(); // 获取总条数 ``` ##### 4. 性能优化建议 - 启用合理化查询防止超大数据查询: ```properties mybatis-plus.pagehelper.reasonable=true ``` - 对于复杂查询,覆盖 `PaginationInnerInterceptor` 的 `beforeQuery` 方法优化 COUNT 语句[^2] #### 验证步骤 1. 检查控制台 SQL 日志,确认生成 `LIMIT ? , ?` 语句 (正确日志示例:`SELECT COUNT(1) FROM user; SELECT id,name FROM user LIMIT 0,10`) 2. 调试检查 `page.getRecords()` 数据内容 3. 确认 `page.getTotal()` 值是否预期总条数一致 > **注意**:MyBatis-Plus 页插件 `PaginationInnerInterceptor` 要求严格遵循参数顺序和 SQL 规范[^3]。通过上述配置和代码规范,可解决 99% 的页数据缺失问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

strggle_bin

一毛不嫌少,十元不嫌多

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值