spring-boot-starter-data-jpa 2.6.4 依赖于 spring-data-jpa 2.6.2,后者依赖于 hsqldb 2.5.2 和 hibernate 5.6.7.Final
当我们想在 CrudRepository 中查询类型为 java.sql.Timestamp 的多个值时,即
@Query("SELECT dm " +
" FROM DataModel dm " +
"WHERE (dm.ts1 IS NULL OR :ts1 IS NULL OR dm.ts1 < :ts1) " +
" AND (dm.ts2 IS NULL OR :ts2 IS NULL OR dm.ts2 < :ts2)")
List<DataModel> findByTimestamps(@Param("ts1") Timestamp ts1, @Param("ts2") Timestamp ts2);
它失败了
org.hsqldb.HsqlException:转换中不兼容的数据类型
spring-data-jpa 2.6.3 也会发生这种情况
降级到 hsqldb 2.5.1 有效
重现 repo : https://github.com/daveyx/spring-data-hsqldb-timestamp-issue
问题出现在 org.hsqldb.jdbc.JDBCPreparedStatement#setTimestamp(int, java.sql.Timestamp, java.util.Calendar)
中,因为参数类型错误。
在 JDBCPreparedStatement#setTimestamp 中,@Param 注释参数的“IS NULL”部分似乎导致“CharacterType”而不是“DateTimeType”。
最佳答案
如您所述,问题是由条件 OR :ts1 IS NULL
和 OR :ts2 IS NULL
引起的。 Hibernate 以 ? 的形式将这些应用于 SQL 查询。 IS NULL
并且 HSQLDB 将参数解析为字符串。 Hibernate 然后假定参数类型已解析为 java.sql.Timestamp 并调用 setTimestamp(int, Timestamp) 方法,这导致了问题。
您可以添加 CAST 来确定参数的类型。
@Query("SELECT dm " +
" FROM DataModel dm " +
"WHERE (dm.ts1 IS NULL OR CAST(:ts1 AS TIMESTAMP) IS NULL OR dm.ts1 < :ts1) " +
" AND (dm.ts2 IS NULL OR CAST(:ts2 AS TIMESTAMP) IS NULL OR dm.ts2 < :ts2)")
HSQLDB 版本 2.5.1 对 setTimestamp(int, Timestamp)
很宽松,当目标不是时间戳时将时间戳转换为字符串。版本 2.5.2 和 2.6.0 中的回归使其变得严格。 HSQLDB 的 future 版本将恢复为宽松的方法。
关于hibernate - 当使用 spring-data-jpa 2.6.2 的 java.sql.Timestamp 查询 IS NULL 时,hsqldb 中转换的不兼容数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71836247/