最近我将一个项目迁移到Sping Boot 3和Java 17。新的Hibernate 6版本似乎有很多bug?
我遇到并调试到死的问题是,在H2上运行的测试中,IN子句没有被正确翻译。我们有一个以以下格式动态构建的查询:DELETE FROM LqTable WHERE (calcId,Nr) IN (SELECT calc.calcId,lpqv2.Nr FROM LqTable lpqv2 JOIN CalcTable calc ON calc.calcId=lpqv2.calcId WHERE (calc.pId, lpqv2.Nr) IN ((?1,?2),(?3,?4)))
当执行时(查询是使用JPA的实体管理器执行的),我们得到这个错误:
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column count does not match; SQL statement:
DELETE FROM LqTable WHERE (calcId,Nr) IN (SELECT (calc.calcId,lpqv2.Nr) FROM LqTable lpqv2 JOIN CalcTable calc ON calc.calcId=lpqv2.calcId WHERE (calc.pId=? and lpqv2.Nr) or
(calc.pId=? and lpqv2.Nr))
[21002-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.get(DbException.java:188)
at org.h2.value.ValueRow.compareTypeSafe(ValueRow.java:119)
at org.h2.value.Value.compareToNotNullable(Value.java:2634)
at org.h2.value.Value.compareTo(Value.java:2607)
at org.h2.value.ValueRow.compareTypeSafe(ValueRow.java:124)
at org.h2.value.Value.compareToNotNullable(Value.java:2634)
at org.h2.value.Value.compareTo(Value.java:2607)
at org.h2.value.CompareMode.compare(CompareMode.java:280)
at org.h2.value.CompareMode.compare(CompareMode.java:20)
at java.base/java.util.TreeMap.getEntryUsingComparator(TreeMap.java:374)
at java.base/java.util.TreeMap.getEntry(TreeMap.java:344)
at java.base/java.util.TreeMap.get(TreeMap.java:279)
at org.h2.result.LocalResult.containsDistinct(LocalResult.java:249)
at org.h2.expression.condition.ConditionInQuery.getValue(ConditionInQuery.java:95)
at org.h2.expression.condition.ConditionInQuery.getValue(ConditionInQuery.java:55)
at org.h2.expression.Expression.getBooleanValue(Expression.java:332)
at org.h2.command.dml.FilteredDataChangeStatement.nextRow(FilteredDataChangeStatement.java:73)
at org.h2.command.dml.Delete.update(Delete.java:58)
at org.h2.command.dml.DataChangeStatement.update(DataChangeStatement.java:74)
at org.h2.command.CommandContainer.update(CommandContainer.java:169)
at org.h2.command.Command.executeUpdate(Command.java:252)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:209)
at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:169)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.sql.exec.internal.StandardJdbcMutationExecutor.execute(StandardJdbcMutationExecutor.java:84)
... 204 common frames omitted
从我所能说的来看,H2Dialect的翻译过程似乎是错误的:DELETE FROM LqTable WHERE (calcId,Nr) IN (SELECT (calc.calcId,lpqv2.Nr) FROM LqTable lpqv2 JOIN CalcTable calc ON calc.calcId=lpqv2.calcId WHERE (calc.pId=? and lpqv2.Nr) or (calc.pId=? and lpqv2.Nr))
这里的问题,除了它改变了IN子句之外,还在于子查询开始处的语法不正确(SELECT **(**calc.calcId,lpqv2.Nr**)** FROM LqTable
,括号不应该在那里。
我已经尝试了从6.0.0到6.1.7的每个版本的Hibernate 6,以及从3.0.0到3.1.0的所有Sping Boot 版本,但没有任何变化。我也尝试过将其作为本机查询执行,但最终执行的SQL在某种程度上更加混乱。
我已经调试了hibernate代码,我得出的结论是,这种混乱的原因是,在翻译查询时,hibernate通过检查H2Dialect的版本来检查子查询中是否支持In子句,但这是0.0.0版本。(这是在AbstractSqlAstTranslator的第4281行检查的,它基本上调用了H2SqlAstTranslator.supportsRowValueConstructorSyntaxInInList,它检查了我所知道的版本是否比1.4.197更新)。
从我可以告诉这似乎是一个错误?有人遇到过这样的事情吗?有什么办法解决这个问题吗?
1条答案
按热度按时间b5lpy0ml1#
这似乎在
6.2.4
版本中得到了修复,至少是暂时的。(H2Dialect的默认构造函数从版本1.4.197
开始,而不是0.0.0
,supportsRowValueConstructorSyntaxInInList
默认为true)。但对我们来说,这个版本引入了新的未解决的问题...因此,如果任何人遇到相同的问题或类似的问题,我发现以下一组属性可以为无效版本提供解决方案:
请注意,这仅适用于测试配置。
编辑:这似乎也是由
hibernate.temp.use_jdbc_metadata_defaults=false
引起的