You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebird Hibernate方言分页参数顺序错误问题求助

Firebird 2.5 + Hibernate 6.x 自定义原生查询分页时first/skip参数顺序错位问题

环境配置

  • Firebird 2.5
  • Hibernate 6.2 或 6.5
  • Spring Data JPA(基于PagingAndSortingRepository)

问题描述

调用自定义原生查询方法并传入page>0的Pageable对象时,Hibernate自动生成的SQL中skip和first参数顺序颠倒,导致Firebird抛出语法错误。但使用标准方法(如repository.findAll(paging))时,参数顺序是正确的。

代码示例

控制器代码

Pageable paging = PageRequest.of(1, 10);
Page<MaterialBrand> items = repository.findByMaterialSizesQuery(25, paging);

仓库代码

@Query(
    value = "select t_m_brands.id...... where gmin <= :size and gmax >= :size",
    nativeQuery = true
)
Page<MaterialBrand> findByMaterialSizesQuery(@Param("size") Float size, Pageable pageable);

错误现象

Hibernate生成的错误SQL:

select skip ? first ? t_m_brands.id,....

触发的错误:

内部服务器错误(状态码500),无法预编译语句[动态SQL错误;SQL错误码=-104;未知标记 - 第1行,第21列;?[SQLState:42000, ISC错误码:335544634]]

正确的SQL应该是:

select first ? skip ? t_m_brands.id,....

已尝试的无效方案

实现QueryRewriter接口重写查询,但此时查询尚未生成带参数的预编译语句,无法修正参数顺序。

解决方案

方案1:自定义Hibernate方言,修正分页语句生成逻辑

Firebird 2.5要求分页语法为first ? skip ?,但Hibernate 6.x默认的FirebirdDialect对原生查询的分页处理可能适配了更高版本的Firebird(允许skip在前)。我们可以自定义方言覆盖分页逻辑:

import org.hibernate.dialect.FirebirdDialect;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.FirebirdLimitHandler;

public class CustomFirebird25Dialect extends FirebirdDialect {
    @Override
    public LimitHandler getLimitHandler() {
        return new FirebirdLimitHandler() {
            @Override
            public String processSql(String sql, boolean hasOffset) {
                if (hasOffset) {
                    // 强制使用Firebird 2.5要求的first在前、skip在后的语法
                    return sql + " first ? skip ?";
                }
                return super.processSql(sql, hasOffset);
            }
        };
    }
}

然后在Spring配置中指定使用自定义方言:

# application.properties
spring.jpa.properties.hibernate.dialect=com.yourpackage.CustomFirebird25Dialect

方案2:手动在原生查询中编写分页逻辑

放弃依赖Pageable自动插入分页参数,手动计算偏移量并写入SQL,同时指定count查询来支持分页结果的总数统计:

修改仓库代码

@Query(
    value = "select t_m_brands.id...... where gmin <= :size and gmax >= :size first :pageSize skip :offset",
    countQuery = "select count(*) from t_m_brands where gmin <= :size and gmax >= :size",
    nativeQuery = true
)
Page<MaterialBrand> findByMaterialSizesQuery(
    @Param("size") Float size,
    @Param("pageSize") int pageSize,
    @Param("offset") int offset
);

控制器中计算参数

Pageable paging = PageRequest.of(1, 10);
int offset = paging.getPageNumber() * paging.getPageSize();
Page<MaterialBrand> items = repository.findByMaterialSizesQuery(25, paging.getPageSize(), offset);

方案3:升级Firebird版本(可选)

Firebird 3.0及以上版本支持skip ... first ...的语法顺序,如果业务允许升级数据库,可以解决此兼容性问题。


内容的提问来源于stack exchange,提问作者Zadra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:19:53