MyBatis-Plus 分页查询报错 BadSqlGrammarException:SELECT COUNT() 异常排查与解决
1. 现象描述
在进行优惠券业务开发时,调用分页查询接口 /coupons/page 突然抛出 BadSqlGrammarException。查看后台日志,发现 MyBatis-Plus 自动生成的 COUNT 语句出现了明显的语法错误:
报错核心信息:
▼text复制代码根本原因:SQL 语法错误:SELECT COUNT() FROM coupon 中 COUNT() 缺少参数 数据库报错位置:near ') FROM coupon' at line 1 技术栈:Spring Boot + MyBatis-Plus (3.4.3) + MySQL
正常的统计语句应该是 SELECT COUNT(*) 或 SELECT COUNT(1),但程序生成的 SQL 括号内空空如也,导致 MySQL 解析失败。
2. 原因分析
经过对代码和 MyBatis-Plus 源码逻辑的排查,该问题主要由以下两个因素共同导致:
2.1 MyBatis-Plus Count SQL 优化失败
MyBatis-Plus 在进行分页查询时,默认会开启 optimizeCountSql(Count 优化)。它会尝试通过 jsqlparser 解析原始 SQL,将其转化为更高效的统计语句。
然而,在 MyBatis-Plus 3.4.3 版本中,当实体类(PO)中包含特殊的字段映射(如使用了反引号包裹的保留字 `name`、`specific`)时,优化器可能无法正确推断出统计参数,从而生成了非法的 COUNT()。
2.2 实体类中的保留字冲突
在项目的Coupon类po中可以看到,表中多个字段使用了 MySQL 关键字:
▼java复制代码@TableField("`name`") private String name; @TableField("`specific`") private Boolean specific;
虽然在 SQL 中使用了反引号规避,但在复杂的自动生成场景下,这增加了解析器出错的概率。
3. 解决方案
禁用 Count 优化
最直接且稳妥的解决办法是针对该分页请求禁用 Count 优化。禁用后,MyBatis-Plus 将不再尝试简化统计 SQL,而是使用最通用的 SELECT COUNT(*) FROM (原查询SQL) AS total 方式进行统计。
4. 代码实现
以下是重构后的分页查询逻辑:
▼java复制代码@Override public PageDTO<CouponPageVO> pageQuery(CouponQuery query) { // 1. 构建分页对象 Page<Coupon> page = query.toMpPageDefaultSortByCreateTimeDesc(); // 2. 关键修复:针对某些场景下 COUNT() 生成非法 SQL 的问题,手动禁用 count 优化 page.setOptimizeCountSql(false); // 3. 构建查询条件 String name = query.getName(); Integer type = query.getType(); Integer status = query.getStatus(); LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.isNotBlank(name), Coupon::getName, name) .eq(type != null, Coupon::getDiscountType, type) .eq(status != null, Coupon::getStatus, status); // 4. 执行分页查询 this.page(page, wrapper); // 5. 封装结果返回 if (CollUtils.isEmpty(page.getRecords())) { return PageDTO.empty(page); } return PageDTO.of(page, CouponPageVO.class); }
5. 总结
- 谨慎对待关键字:数据库设计时应尽量避开
name,status,specific等关键字。若必须使用,务必在实体类映射时加上反引号。 - 版本避坑:MyBatis-Plus 3.4.x 系列的 Count 优化在某些复杂场景下确实存在不稳定性。如果遇到
BadSqlGrammarException且指向 Count 语句,优先考虑通过page.setOptimizeCountSql(false)绕过。
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
