【问题标题】:Introducing a named parameter breaks jOOQ query引入命名参数会中断 jOOQ 查询
【发布时间】:2020-10-17 02:24:48
【问题描述】:

要查询 PostgreSQL 10.11 数据库,我使用的是 jOOQ 3.12.4,它与 Spring Boot 2.2 捆绑在一起。

假设我使用 jOOQ 构建了一个查询,如下所示:

final String[] ids = ...;

final var query = dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.in(ids));
final Map<String, List<MyTable>> changeDomains = query.fetch().intoGroups(MY_TABLE.ID, MyTable.class);

此代码运行良好并产生预期结果。但是当我重构我的查询并引入一个命名参数(以在我的代码的多个部分重用查询)时,如下所示:

final String[] ids = ...;

final var query = dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.in(param("ids")));
final Map<String, List<MyTable>> changeDomains = query.bind("ids", ids).fetch().intoGroups(MY_TABLE.ID, MyTable.class);

我突然开始收到以下错误:

org.springframework.jdbc.BadSqlGrammarException: jOOQ; bad SQL grammar ...; nested exception is org.postgresql.util.PSQLException: ERROR: operator does not exist: text = character varying[]
    Hinweis: No operator matches the given name and argument type(s). You might need to add explicit type casts.

编辑:我在使用时遇到同样的错误

MY_TABLE.ID.in(param("ids", String[].class))

改为。

我该如何解决或解决这个问题?

【问题讨论】:

  • 你为什么要创建一个参数?
  • @SimonMartinelli 我想在我的代码的多个部分重用查询。因此,应该可以重新绑定参数,从而使查询适应这些代码部分的实际需求。
  • 你可以试试 param("ids", String[].class)
  • @SimonMartinelli 我试过了,我得到了完全相同的错误。

标签: java sql postgresql jooq


【解决方案1】:

代码重用方法的更好解决方案

但是当我重构我的查询并引入一个命名参数(在我的代码的多个部分中重用查询)时

虽然您可以以这种方式使用 jOOQ(请注意,以非线程安全的方式更改和重用 jOOQ 查询时!),通常建议以更实用的方式使用 jOOQ,例如:

重用 jOOQ 查询不会获得太多收益,具体而言,几乎没有任何性能提升。

所以,不要这样:

final var query = dslContext.selectFrom(MY_TABLE)
    .where(MY_TABLE.ID.in(param("ids")));
final Map<String, List<MyTable>> changeDomains = query
    .bind("ids", ids).fetch().intoGroups(MY_TABLE.ID, MyTable.class);

这样写:

public ResultQuery<MyTableRecord> query(String[] ids) {
    return dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.in(ids));
}

// And then:
final Map<String, List<MyTable>> changeDomains = query(ids)
    .fetch().intoGroups(MY_TABLE.ID, MyTable.class);

你遇到的实际问题:

jOOQ、JDBC 和 SQL 不支持单个绑定值 IN 列表。虽然这样写似乎很有用:

SELECT * FROM t WHERE c IN (:bind_value)

并且将数组或列表作为单个绑定值传递,这在 SQL 中不受支持。某些 API 可能会假装支持此功能(但在幕后将单个绑定值替换为多个 ?, ?, ..., ?

PostgreSQL 支持带有数组的 = ANY (:bind_value) 运算符

SELECT * FROM t WHERE c = ANY (:bind_value)

你可以在 jOOQ 中使用它

dslContext.selectFrom(MY_TABLE).where(MY_TABLE.ID.eq(any(ids)));

这样,您可以在执行之前调用bind() 方法来替换数组。但是,我仍然建议您编写动态返回查询的函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 2015-12-13
    • 2011-06-07
    • 2011-10-21
    • 2019-04-14
    相关资源
    最近更新 更多