SpringBootTest 由于 PageRequest 而出现 h2 v2.1.214 错误

phi*_*g31 3 h2 spring-boot

从 Spring boot 2.5.6 升级到 2.7.3 后,我有一些测试错误。

作为信息,我们使用 Oracle 作为数据库,使用 h2 进行测试。

我有一些测试失败,出现以下错误:

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException
Run Code Online (Sandbox Code Playgroud)

事实上,h2的版本之前是1.4.200,现在是2.1.214,很多东西似乎都发生了变化。根据错误的测试,错误的原因并不总是相同的。有时这是一个未找到表的错误(尚未解决),有时是一个“类型“BOOLEAN”和“INTEGER”的值不可比较”的错误(通过更新与像这样的布尔列myBoolean = 0,它已更新为myBoolean = false) 并且我在使用 PageRequest 完成的查询上也有错误。

对于最后一种情况,我有一个像这样的控制器:

public Page<MyEntity> doSomething() {
    final Sort sort = Sort.by(Order.desc("column1"));
    final PageRequest pageRequest = PageRequest.of(0, 1000, sort);
    return myEntityRepository.findAll(pageRequest);
}
Run Code Online (Sandbox Code Playgroud)

但我有一个这样的错误:

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "select myentity0_.id as id1_47_, myentity0_.column1 as column1_47_, myentity0_.column2 as column2_47_ from my_table myentity0_ order by myentity0_.column1 desc [*]limit ?"; SQL statement:
select myentity0_.id as id1_47_, myentity0_.column1 as column1_47_, myentity0_.column2 as column2_47_ from my_table myentity0_ order by myentity0_.column1 desc limit ? [42000-214]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:502)
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:477)
    at org.h2.message.DbException.get(DbException.java:223)
    at org.h2.message.DbException.get(DbException.java:199)
    at org.h2.message.DbException.getSyntaxError(DbException.java:247)
    at org.h2.command.Parser.getSyntaxError(Parser.java:898)
    at org.h2.command.Parser.prepareCommand(Parser.java:572)
    at org.h2.engine.SessionLocal.prepareLocal(SessionLocal.java:631)
    at org.h2.engine.SessionLocal.prepareCommand(SessionLocal.java:554)
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1116)
    at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:92)
    at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:288)
    at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:337)
    at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:149)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:176)
    ... 205 more
Run Code Online (Sandbox Code Playgroud)

如果我像这样更改控制器,则测试成功:

public Page<MyEntity> doSomething() {
    List<MyEntity> result = myEntityRepository.findAll();
    return new PageImpl<MyEntity>(result);
}
Run Code Online (Sandbox Code Playgroud)

所以看来问题是由于使用 PageRequest 造成的。

请问你有什么想法吗?

Evg*_*nov 8

Java 持久性库通常仅在 H2 的默认常规模式下进行测试,可能无法在其他模式下正常工作。

Oracle 不支持 MySQL/PostgreSQL 风格LIMIT,H2 也不允许在 Oracle 兼容模式下使用,但有些库为 H2 生成LIMIT而不是标准OFFSET/ FETCH

Spring Data JDBC (spring-data-relational) 大约一个月前才添加了对 H2 自定义兼容模式的支持,并且包含此修复的 2.4.3 版本尚未发布。

Hibernate ORM 6.*.* 应该可以正常工作,但 Hibernate ORM 5.6.* 有一个已知问题: https://hibernate.atlassian.net/jira/software/c/projects/HHH/issues/HHH-15318

您可以LIMIT在 H2 的 Oracle 兼容模式下启用作为临时解决方法。为此,您需要在应用程序初始化期间执行以下 Java 代码:

org.h2.engine.Mode mode = org.h2.engine.Mode.getInstance("ORACLE");
mode.limit = true;
Run Code Online (Sandbox Code Playgroud)

  • 因为当你使用H2时,你也需要使用`H2Dialect`,即使你使用H2的某些兼容模式,你也不能使用也不应该尝试使用`OracleDialect`或其他方言。但是旧版本的 Hibernate ORM 和其他一些库中的“H2Dialect”会生成“LIMIT”,2014 年发布的 H2 1.3.176 和旧版本与现代版本不同,使用该子句而不是标准子句。 (2认同)