oracle分页必须配置helperdialect: oracle,否则pagehelper按mysql语法生成limit语句,导致ora-00933错误;深分页需用offset...fetch或row_number()优化,避免rownum嵌套性能断崖。

Oracle分页必须配 helperDialect: oracle
不设这个参数,PageHelper会按MySQL语法生成LIMIT语句,直接报ORA-00933: SQL command not properly ended。哪怕你用的是Oracle 12c+,也别指望它自动识别——PageHelper不会探测数据库版本,只认配置。实际项目中,我们见过因漏配该参数导致测试通过、上线后全量接口500的事故。
深分页(pageNum > 100)必须改用游标分页
Oracle传统ROWNUM嵌套写法在深分页时性能断崖式下跌,本质是每次都要从头扫描前(pageNum−1)×pageSize行。比如查第1000页、每页20条,就得跳过19980行再取20条。
- 优先用Oracle 12c+的
OFFSET ... FETCH NEXT语法(需helperDialect: oracle且PageHelper ≥ 5.3.0) - 老版本Oracle(11g)必须手写
ROW_NUMBER() OVER (ORDER BY ...)子查询,避免两层ROWNUM - 绝对不要在分页SQL里带
ORDER BY字段上缺失索引,否则执行计划会走全表扫描
MyBatis-Plus和PageHelper不能共存
两者都通过MyBatis拦截器实现分页,同时启用会导致:
-
PageInterceptor和PaginationInnerInterceptor冲突,分页失效或COUNT查错 - Oracle下可能生成
SELECT COUNT(*) FROM (SELECT ...)嵌套结构,而外层COUNT无法利用索引 - 日志里反复出现
intercepted method: query,但结果集没分页
解决方案:二选一。若已用MyBatis-Plus,就删掉pagehelper-spring-boot-starter;若坚持用PageHelper,得排除MP自带的分页插件:mybatis-plus-boot-starter里exclusions掉com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor。
存储过程分页要显式注册Types.OTHER
Oracle存储过程返回SYS_REFCURSOR时,JDBC默认不识别。不注册类型会抛ORA-06550: PLS-00306: wrong number or types of arguments。
MyBatis XML中必须这样写:
<select id="callPagingProc" statementtype="CALLABLE">
{CALL P_FENYE(
#{pageNo,jdbcType=NUMERIC},
#{pageSize,jdbcType=NUMERIC},
#{result,mode=OUT,jdbcType=OTHER,resultMap=userResultMap}
)}
</select>
关键点:jdbcType=OTHER不能省,resultMap要提前定义好字段映射,且mode=OUT必须明确——Oracle不接受IN OUT或纯IN的ref cursor参数。
真正卡住人的往往不是语法,而是Oracle分页里那些“看起来合理但实际无效”的写法:比如以为reasonable: true能解决越界问题,却忽略了它对Oracle的OFFSET计算毫无影响;又比如在存储过程中手动CLOSE p_result,导致JDBC连接池拿到已关闭的cursor。这些细节不验证执行计划,光看日志根本发现不了。











