绑定 OffsetDateTime 时出错 [运算符不存在:时区时间戳 <= 字符变化]

Error binding OffsetDateTime [operator does not exist: timestamp with time zone <= character varying]

我们正在尝试执行删除基于 ZonedDateTime 的记录的 dml。我们正在使用以下代码,但 运行 出错。

dsl.execute ("delete from fieldhistory where createddate <= ? and object = ?", beforeDate.toOffsetDateTime(), objName)

其中 beforeDate 是 ZonedDateTime,objectName 是字符串

我们收到来自 postgres 的以下错误。

org.jooq.exception.DataAccessException: SQL [delete from fieldhistory where createddate <= ? and object = ?]; ERROR: operator does not exist: timestamp with time zone <= character varying
  Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
  Position: 56
    at org.jooq_3.13.1.POSTGRES.debug(Unknown Source)
    at org.jooq.impl.Tools.translate(Tools.java:2751)
    at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:755)
    at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:385)
    at org.jooq.impl.DefaultDSLContext.execute(DefaultDSLContext.java:1144)

问题是,我们如何在 Jooq 中绑定日期时间值?

由于历史原因,jOOQ 将所有 JSR-310 时间绑定为字符串,而不是相关的 object 类型。这是因为直到最近,JDBC drivers 还没有原生支持 JSR-310 类型,因此,使用字符串是一个不错的默认值。

不幸的是,这会导致类型歧义,如果出现以下情况,您将不会出现歧义:

  • jOOQ 没有绑定字符串
  • 您使用的是代码生成器,因此键入安全的 DSL API 方法

作为解决方法,您可以做一些事情,包括:

显式转换绑定变量

dsl.execute("delete from fieldhistory where createddate <= ?::timestamptz and object = ?",  
    beforeDate.toOffsetDateTime(), 
    objName)

使用 DSL API

dsl.deleteFrom(FIELDHISTORY)
   .where(FIELDHISTORY.CREATEDDATE.lt(beforeDate.toOffsetDateTime()))
   .and(FIELDHISTORY.OBJECT.eq(objName))
   .execute();

通过编写自己的绑定

您可以编写自己的数据类型绑定并将其附加到生成的代码,或您的普通 SQL 查询,在这种情况下,您可以控制绑定变量如何发送到 JDBC driver。看: https://www.jooq.org/doc/latest/manual/sql-building/queryparts/custom-bindings/

例如:

DataType<OffsetDateTime> myType = SQLDataType.OFFSETDATETIME
                                             .asConvertedDataType(new MyBinding());
dsl.execute ("delete from fieldhistory where createddate <= {0} and object = {1}", 
    val(beforeDate.toOffsetDateTime(), myType), 
    val(objName))

将来会修复这个问题,因此不再需要:https://github.com/jOOQ/jOOQ/issues/9902