升级至Hibernate 6后setFirstResult/setMaxResults生成PostgreSQL错误SQL
问题根源
你遇到的SQL语法错误,核心原因是Hibernate 6.x与PostgreSQL的方言配置不匹配,导致生成了不符合PostgreSQL语法规范的分页语句。错误SQL中的offset ? rows fetch first ? rows only写法存在语法冲突——虽然PostgreSQL单独支持OFFSET ? ROWS或FETCH FIRST ? ROWS ONLY,但旧版Hibernate通用方言在拼接这两个子句时会出现语法错误。
另外需要注意:你的分页参数计算逻辑需要和传入参数的含义匹配,如果start本身就是偏移量而非页码,当前的start = (start - 1) * count会导致偏移量被错误放大,但这不是本次语法错误的直接原因。
解决方案
1. 修正Hibernate方言配置
在持久化配置文件(如persistence.xml)或Spring配置中,替换为适配你PostgreSQL版本的具体方言:
- 若使用PostgreSQL 10+,配置:
hibernate.dialect=org.hibernate.dialect.PostgreSQL10Dialect
- 若使用PostgreSQL 15+,配置:
hibernate.dialect=org.hibernate.dialect.PostgreSQL15Dialect
Hibernate 6.x不再推荐使用通用的PostgreSQLDialect,版本专属方言会生成符合对应PostgreSQL版本的标准分页SQL,彻底解决语法拼接问题。
2. 校验分页参数逻辑
确认传入setPagination的start参数类型:
- 如果是页码(从1开始),当前的
start = (start - 1) * count计算逻辑正确; - 如果是偏移量(从0开始),需删除多余计算,直接使用原始值:
protected void setPagination(int start, int count, TypedQuery<?> query) { if (count > 0) { query.setFirstResult(start); query.setMaxResults(count); } }
3. 版本兼容性验证
你当前使用的PostgreSQL驱动42.7.1与Hibernate 6.4.4.Final是兼容的,只需确保PostgreSQL服务器版本在驱动支持范围内(42.7.x支持9.6~16版本)。
验证效果
修改方言配置后,Hibernate会生成PostgreSQL可正确解析的分页SQL,例如:
ORDER BY 2 OFFSET ? FETCH FIRST ? ROWS ONLY
或
ORDER BY 2 LIMIT ? OFFSET ?
执行查询后将不再出现语法错误。
内容的提问来源于stack exchange,提问作者paresh

