为啥这个 JPA 查询在 H2 数据库上失败?

Posted

技术标签:

【中文标题】为啥这个 JPA 查询在 H2 数据库上失败?【英文标题】:Why does this JPA query fail on a H2 database?为什么这个 JPA 查询在 H2 数据库上失败? 【发布时间】:2022-01-19 16:41:57 【问题描述】:

我在 Spring Data 接口中定义了以下 JPA 查询

@Query("select tr.bidder.supplierId " +
    "from   TaskResponse tr " +
    "where  tr.task.id = :taskId " +
    "and    tr.extended = true " +
    "and    tr.bidder.supplierId not in (:extendedSupplierIds)")
Set<String> supplierIdsDueTaskRevocationNotification(UUID taskId,
        Set<String> extendedSupplierIds);

查询在对 Postgres 数据库执行时工作正常,但在对 H2 数据库执行时失败并出现以下错误:

Syntax error in SQL statement 

SELECT BIDDER1_.SUPPLIER_ID AS COL_0_0_ 
FROM TASK_RESPONSES TASKRESPON0_ 
CROSS JOIN BIDDERS BIDDER1_ 
WHERE TASKRESPON0_.BIDDER_ID=BIDDER1_.ID 
AND TASKRESPON0_.TASK_ID=? 
AND TASKRESPON0_.EXTENDED=1 
AND (BIDDER1_.SUPPLIER_ID NOT IN  ()[*])"; 

expected "NOT, EXISTS, INTERSECTS, UNIQUE"; 

看起来问题出在not in (:extendedSupplierIds) 谓词上,因为如果我删除这个谓词,查询在两个数据库上执行时都不会出错。

有没有办法我可以重写查询,以便它可以在两个数据库上工作?

更新

根据一位受访者的建议,我将查询更改为使用显式联接

@Query("select b.supplierId " +
    "from   TaskResponse tr " +
    "join   tr.bidder b " +
    "join   tr.task t " +
    "where  t.id = :taskId " +
    "and    tr.extended = true " +
    "and    b.supplierId not in (:extendedSupplierIds)")
Set<String> supplierIdsDueTaskRevocationNotification(UUID taskId,
        Set<String> extendedSupplierIds);

但这并没有什么不同,我仍然得到同样的错误。

【问题讨论】:

您是否也将方言更改为 H2Dialect? @Turo 是的,我做到了 两个数据库发出的SQL是什么?为 :extendedSupplierIds 传递了什么,并且由于它是一个集合,“tr.bidder.supplierId 不在 :extendedSupplierIds”中是否有效或没有括号有效?似乎很奇怪,错误不会显示带有一系列“?”的 SQL 语句。括号之间 【参考方案1】:

这是由错误引起的,可能在 org.hibernate.dialect.H2Dialect 中。

如果您将空集作为查询参数值传递,该值构成 JPQL 查询中“不在”谓词的右侧,则在针对 H2 数据库运行时查询会失败。要解决此问题,请使用 Set 包含 而是一个空元素。

例如在您调用此查询时使用

UUID taskId = UUID.randomUUID();
Set<String> supplierIds = // get this from somewhere

if (supplierIds.isEmpty()) 
  supplierIds.add(null);


myRepository.supplierIdsDueTaskRevocationNotification(taskId, supplierIds)

【讨论】:

以上是关于为啥这个 JPA 查询在 H2 数据库上失败?的主要内容,如果未能解决你的问题,请参考以下文章

带有 Spring JPA 的 H2 中的几何数据类型

使用 JPA (Eclipselink) 在 H2 数据库中执行全文搜索

无法在 h2 内存数据库中插入数据

H2 查询失败,“节点没有数据类型:org.hibernate.hql.internal.ast.tree.MethodNode”

使用 Spring Embedded Database 的 JPA 未找到记录

为啥需要在执行修改查询之前清除 jpa 持久性上下文?