mysql分页查询报错,及解决

针对MySQL分页查询报错的问题,介绍了四种优化方法:单步改分步查询、子查询、分步查询唯一字段再组装及缩小粒度,并分析了各种方法的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mysql分页查询报错:
前提:
1.每页1000条数据
2.查到57页的时候,就报错了
以下是错误信息:

org.springframework.jdbc.UncategorizedSQLException:
### Error querying database. Cause: java.sql.SQLException:
...省略中间...
received message larger than max (18441058 vs. 16777216)
### The error may exist in sqlmap/RxOrder.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT ...省略中间查询... LIMIT ?,?
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:71)
...省略后面

关于这个错误,网上几乎没有太多可用记录,最初就猜想是分页太深,导致内存满了,毕竟是内存排序,最后找公司同事确认了,就是这个原因

解决方式就是优化sql,避开深度分页

原sql:
select * from table01 where id > 1000000000000 and id < 9000000000000
limit 57000,1000
sql的目的是分页查出所有的数据,但因为分页太深,导致数据库内存爆满,查询就停止了

优化方案1(单步改分步查询):
select id from table01 where id > 1000000000000 and id < 9000000000000
limit 56999,1
第一步,先查出第56999条的id
select * from table01 where id > #{id} and id < 9000000000000
limit 57000,1000
第二步,直接从这个id开始向后拿1000条


优化方案2(子查询):
select id from table01 where 
id > (select id from table01 where id > 1000000000000 and id < 9000000000000
limit 56999,1)
and id < 9000000000000
limit 1000
原理和优化方案1一样,只不过放在一个sql中了,但是数据量大的数据库一般都分库分表,至少也是分片,所以对子查询的支持不是很好,因业务系统而异

优化方案3(分步查询唯一字段,再组装):
select id from table01 where id > 1000000000000 and id < 9000000000000
limit 57000,1000
先查出id的集合list,再遍历这个集合,分别查出每个id对应的数据,再组装起来
这样的好处是将数据库的内存压力变相的转移到服务器,一般服务器还是可以抗住的
但这样的缺点也明显,就是多了层查询,会慢些

优化方案4(缩小粒度):
业务原因,原来分页是以天为最小粒度,每天是个线程,每个线程再查所有
优化的话可以考虑以小时为一个最小粒度,每个小时是一个线程,那么每个小时的数据量就没那么大了,分页也就不会太深了

总结:一切优化的根本目的都是为了避开一次性的大数据量的分页
### MyBatis 分页插件配置启动报错解决方案 #### 插件版本兼容性问题 在使用 `PageHelper` 进行分页操作时,如果遇到 `java.lang.ClassCastException: com.github.pagehelper.PageHelper cannot be cast to org.apache.ibatis.plugin.Interceptor` 错误,则可能是由于使用的 `PageHelper` 和 `PageInterceptor` 版本不匹配所引起的。确保这两个组件的版本一致可以有效减少此类异常的发生[^1]。 对于依赖管理工具 Maven 来说,在项目的 pom.xml 文件中指定合适的 mybatis-pagehelper 以及其拦截器的具体版本号非常重要: ```xml <dependencies> <!-- other dependencies --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>最新稳定版</version> </dependency> <!-- Ensure the version of pagehelper and its interceptor match --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>相应版本</version> </dependency> </dependencies> ``` #### 数据库方言设置不当引发 SQL 拼接错误 另一个常见问题是当应用程序尝试访问不同类型的数据库(例如从 MySQL 切换到 SQL Server),而未正确调整 PageHelper 的 dialect 参数时发生的 SQL 语法差异导致的错误。比如,默认情况下 PageHelper 使用 LIMIT 关键字来实现分页功能,这适用于 MySQL;但对于 SQLServer 应该采用 TOP 或者 OFFSET-FETCH 子句来进行分页处理[^2]。 为了适应不同的 RDBMS 平台并避免上述提到的 SQL 语句拼接失误,可以在 application.properties (或 .yml) 中显式声明目标数据库对应的 Dialect 类型: ```properties # For SQL Server, set this property accordingly. spring.datasource.platform=sqlserver mybatis.configuration.map-underscore-to-camel-case=true pagehelper.dialect=sqlserver2017 ``` 或者通过 Java 配置类的形式注册自定义的 PageInterceptor 实现,并传入相应的参数对象以指明当前环境下的 DB 方言特性。 #### 不恰当的方法调用顺序造成的影响 有时即使解决了前面两个方面的问题之后仍然会遭遇诸如 “自动添加 limit 导致分页失败” 的情况。这类现象通常是因为 PageHelper 方法被放置在一个不适合的位置上被执行所致。理想状态下应该是在执行查询之前立即调用 startPage() 函数开启分页模式,而在获取结果集后再关闭它[^4]。 以下是推荐的做法: ```java // 正确的方式:先启动分页再做查询 PageHelper.startPage(pageNum, pageSize); List<User> users = userMapper.selectAll(); PageInfo<User> pageInfo = new PageInfo<>(users); // 错误示范:将分页逻辑放在非查询方法前 PageHelper.offsetPage(startRow, size); // 不建议在此处调用此方法 User user = userService.getById(userId); // 查询单条记录不会触发分页机制 ``` 综上所述,要成功解决 MyBatis 分页查询配置期间可能出现的各种启动报错状况,需注意以下几个要点: - 确认所有涉及的第三方库及其内部模块之间的版本协调; - 明确设定针对特定关系型数据库系统的分页指令格式; - 调整业务代码结构使之遵循最佳实践指导方针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值