【问题标题】:JPA and Oracle DB: Distinct query with pagination leads to Error: ORA-00909: Invalid amount of argumentsJPA 和 Oracle DB:分页的不同查询导致错误:ORA-00909:参数数量无效
【发布时间】:2022-01-12 15:16:02
【问题描述】:

我正在运行一个带有 oracle 数据库的 spring 后端。 我使用规范 API 来执行查询:

@Slf4j
public class ContentSpecification implements Specification<Content> {

  private final transient ContentFilter filter;

  public ContentSpecification(final ContentFilter filter) {
    this.filter = filter;
  }

  @Override
  public Predicate toPredicate(
      @NonNull final Root<Content> root,
      @NonNull final CriteriaQuery<?> query,
      @NonNull final CriteriaBuilder builder) {
    final List<Predicate> predicates = new ArrayList<>();

    if (!isEmpty(filter.getTerm())) {
      // ... not relevant

      predicates.add(builder.or(title, subtitle, body, keywords));
    }
    
    query.distinct(true);

    return builder.and(predicates.toArray(new Predicate[0]));
  }
}
  public PagedModel<ContentModel> getContent(
      final String term,
      final Integer page,
      final Integer size) {

    final int pageSize = size == 0 ? MAX_VALUE : size;

    return pagedAssembler
        .toModel(
            repository.findAll(
                new ContentSpecification(
                    new ContentFilter(term)),
                PageRequest.of(page, pageSize)),
            contentAssembler);
  }

这与 H2 和 MySQL 数据库完美配合。 但是一旦我使用 Oracle 数据库,它就无法工作:

spring:
  datasource:
    driver-class-name: oracle.jdbc.OracleDriver
    initialization-mode: never
    url: <url>
    username: <user>
    password: <pw>
  jpa:
    database-platform: org.hibernate.dialect.Oracle12cDialect
    hibernate:
      ddl-auto: validate
    properties:
      hibernate:
        format_sql: true
        current_session_context_class: org.springframework.orm.hibernate5.SpringSessionContext
    show-sql: true

我得到的控制台输出如下:

2021-12-07 15:24:22.487  INFO [my-service,4d641a9f03674994,4d641a9f03674994,false] 14244 --- [nio-8082-exec-7] d.b.b.p.p.content.ContentController      : get content: null, null, null, 0, 5
Hibernate: 
    select
        * 
    from
        ( select
            distinct content0_.id as id2_3_,
            content0_.version as version3_3_,
            content0_.status as status9_3_,
            content0_.status_date as status_date10_3_,
            content0_.subtitle as subtitle11_3_,
            content0_.title as title12_3_,
        from
            content content0_ 
        where
            content0_.status=? ) 
    where
        rownum <= ?
Hibernate: 
    select
        distinct count(distinct content0_.id,
        content0_.version) as col_0_0_ 
    from
        content content0_ 
    where
        content0_.status=?
2021-12-07 15:24:22.508  WARN [my-service,4d641a9f03674994,4d641a9f03674994,false] 14244 --- [nio-8082-exec-7] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 909, SQLState: 42000
2021-12-07 15:24:22.508 ERROR [my-service,4d641a9f03674994,4d641a9f03674994,false] 14244 --- [nio-8082-exec-7] o.h.engine.jdbc.spi.SqlExceptionHelper   : ORA-00909: Invalid amount of arguments
2021-12-07 15:24:22.514 ERROR [my-service,4d641a9f03674994,4d641a9f03674994,false] 14244 --- [nio-8082-exec-7] d.b.b.p.p.ApplicationExceptionHandler    : runtime exception: 

org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
    ...
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
    ... 111 common frames omitted
Caused by: java.sql.SQLSyntaxErrorException: ORA-00909: Ungültige Anzahl von Argumenten
    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:509) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:461) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1104) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:550) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:268) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:655) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:270) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:91) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:807) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:983) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1168) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3666) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.executeInternal(T4CPreparedStatement.java:1426) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3713) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1167) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-3.4.2.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-3.4.2.jar:na]
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57) ~[hibernate-core-5.4.12.Final.jar:5.4.12.Final]
    ... 148 common frames omitted
Caused by: oracle.jdbc.OracleDatabaseException: ORA-00909: Ungültige Anzahl von Argumenten

    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:513) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    ... 165 common frames omitted

只要我删除了 distinctpagination,它也可以与 oracle db 一起使用。

oracle 有没有解决方案让分页和分页一起运行?

编辑

所以看来 oracle 的计数查询失败了。 只是为了比较,用H2下面的sql是 生成:

Hibernate: 
    select
        distinct content0_.id as id2_3_,
        content0_.version as version3_3_,
        content0_.status as status9_3_,
        content0_.status_date as status_10_3_,
        content0_.subtitle as subtitl11_3_,
        content0_.title as title12_3_,
    from
        content content0_ 
    where
        content0_.status=? limit ?
Hibernate: 
    select
        distinct count(distinct (content0_.id,
        content0_.version)) as col_0_0_ 
    from
        content content0_ 
    where
        content0_.status=?

【问题讨论】:

    标签: java spring oracle


    【解决方案1】:

    错误ORA-00909: invalid number of arguments的原因是提供行数的语句

    select
            distinct count(distinct content0_.id,
            content0_.version) as col_0_0_ 
        from
            content content0_
    ...
    

    COUNT(DISTINCT expr,[expr...]) 可能允许这种构造 MySQL

    但在 Oracle 中是非法

    由于您的方言Oracle12cDialect,我怀疑在实体中有多个标识列的情况下,该方言的实现存在问题 。参见例如here 获取正确的 SQL 解决方案。

    还请注意,此查询中的第一个 DISTINCT 是可能的,但完全不相关 作为带有count 的查询将只产生一行-

    话虽如此,您应该 IMO 在您的数据模型中做出一些努力,这将使distinct 的使用没有必要。恕我直言,正确方法。

    【讨论】:

    • 感谢您的解释。为oracle实现休眠的库正在生成sql...但它正在生成非法sql...。
    【解决方案2】:

    实际上是失败的查询:

        select
            distinct count(distinct (content0_.id,
            content0_.version)) as col_0_0_ 
        from
            content content0_ 
        where
            content0_.status=? ```
    

    是一个查询 spring-data 问题以获得可用记录的总量(请检查:org.springframework.data.jpa.repository.support.SimpleJpaRepository#executeCountQuery - 实际上,提供完整的堆栈跟踪是值得的) .并且您的 Content 实体似乎具有复合 PK,即 (id, version)(同样,未提供实体定义),但 HBN 在此类查询中遇到了一些困难:https://hibernate.atlassian.net/browse/HHH-11042

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-02
      • 2018-12-04
      • 1970-01-01
      • 2018-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多