oracle 12c分页需显式配置oracle12cdialect,否则mp默认按11g处理rownum嵌套;动态排序字段${sortfield}须为纯列名,含点号或函数会导致jsqlparser解析失败;多层子查询别名需外层包裹,join分页需禁用optimizejoin。
oracle 12c分页插件默认用rownum,不兼容offset语法
mybatis-plus的paginationinnerinterceptor在检测到oracle方言时,默认按oracle 11g及更早版本处理,生成形如select * from (select ..., rownum rn from (...)) where rn between ? and ?的嵌套sql。但oracle 12c原生支持offset ... fetch next,而mp未自动切换该模式——关键在于它**没识别出你用的是12c+,仍强行套用老式rownum逻辑**,导致嵌套层级错乱或字段别名不可见。
ORDER BY字段用${}拼接时触发解析失败
当你在XML或注解SQL里写ORDER BY ${sortField},MP的SQL解析器JSqlParser会把整个语句当字符串解析。Oracle 12c中若${sortField}值含点号(如t1.name)或函数(如UPPER(t1.name)),JSqlParser无法正确提取排序字段,后续自动生成COUNT语句时直接抛JSQLParserException,最终表现为“SQL syntax error near LIMIT”这类误导性报错。
- 必须确保
${sortField}只传纯列名(如name),不含表别名、函数、表达式 - 若业务强依赖动态排序字段,改用白名单校验 + 字符串拼接,避免直接透传用户输入
- 启用DEBUG日志:
logging.level.net.sf.jsqlparser=DEBUG,看解析器实际卡在哪一步
自定义SQL里多层子查询 + 别名导致COUNT语句失效
这是最隐蔽的坑:你在Mapper里写了带别名的子查询,比如SELECT id, UPPER(name) AS name_upper FROM user t1,MP尝试生成COUNT语句时,会把WHERE name_upper = ?直接塞进COUNT的SELECT COUNT(*) FROM (...) WHERE ...里——但Oracle不允许在WHERE中引用外层SELECT的别名。结果就是语法错误,且错误位置常指向LIMIT(因为MP在重写SQL末尾加了分页参数,掩盖了真实问题点)。
- 解决方法不是删别名,而是给原始查询再套一层:用
SELECT * FROM (原始查询) t0,让别名只存在于内层 - 如果用了
LEFT JOIN,确认PaginationInnerInterceptor的optimizeJoin设为false,否则COUNT语句会直接丢掉JOIN部分 - 别依赖
ew.customSqlSegment往复杂查询里硬塞条件,它不区分作用域层级
方言配置没对上Oracle 12c的真实版本号
MybatisPlusConfig里只配了new OracleTypeHandler()或OracleDialect不够——MP 3.5+要求显式指定数据库版本,否则默认回退到Oracle 11g。你要在PaginationInnerInterceptor构造时传入Oracle12cDialect:
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor() {
return new PaginationInnerInterceptor(new Oracle12cDialect());
}
注意:Maven依赖里mybatis-plus-boot-starter版本必须≥3.4.3.4,低版本压根没有Oracle12cDialect类。
真正卡住人的地方,往往不是语法本身,而是MP在自动生成COUNT和重写SQL时,把Oracle 12c能跑通的写法,悄悄降级成11g兼容模式,还把错误堆栈藏在JSqlParser深处。盯住日志里那条被重写的COUNT语句,比看报错信息有用十倍。











