jOOQ 3.15 postgres 抱怨生成的 jsonb 类型 sql

jOOQ 3.15 postgres complaining about jsonb types in generated sql

将我的 jOOQ 版本从 3.14 -> 3.15.3 升级后弹出以下运行时错误:

ERROR: column "old_values" is of type jsonb but expression is of type character varying

代码如下:

final String jsonChanges = gson.toJson(map);
final InsertOnDuplicateStep<TicketLogRecord> insertLogs =
                insertInto(LOG,
                           LOG.ID,
                           LOG.OLD_VERSION,
                           LOG.OLD_VALUES,
                           LOG.NEW_VALUES)
                .select(
                        select(field("to_update.id", UUID.class),
                                field("to_update.version", Integer.class),
                                val("{}", JsonElement.class),
                                val(jsonChanges, JsonElement.class),
)
final var countUpdated =
                with("to_update", "id", "version", "state_id").as(ids)
                                                                      .with("update_states").as(updateWhere.returning())
                                                                      .with("insert_logs").as(insertLogs.returning())
                                                                      .select(count().as("updated_count"))
                                                                      .from("to_update");
            return using(configuration)
                .fetchOne(countUpdated)
                .getValue("updated_count", Integer.class);

通过在下面的行中使用 cast(val("{}", JsonElement.class), LOG.OLD_VALUES) 和 NEW_VALUES 解决了这个问题。但我感兴趣的是,为什么这两个次要版本之间会出现 SQL 代的问题?

谢谢

为什么会发生这种情况/“倒退”?

这里的用法:

val(jsonChanges, JsonElement.class)

正在使用未记录的“功能”,在某些情况下(并非总是如此)偶然发生。在您的情况下,它似乎对您有用。但是,SQLDataType can be passed to methods like DSL.val(Object, Class) 只支持 class 个文字,所以这是有效的:

field("to_update.version", Integer.class)

但通过 JsonElement 不是。 jOOQ 不可能知道您打算如何将 JsonElement 值绑定到 JDBC 驱动程序。它可能有效,因为在某个地方,您已经注册了一个 Binding<Object, JsonElement>,并且因为该绑定(历史上)被添加到内部静态 DataType 注册表中,查找 JsonElement.class 的绑定碰巧有时工作。它可能不起作用的原因:

  • 注册Binding<Object, JsonElement>的class还没有加载
  • jOOQ 中的内部重构改变了其中一些未记录的查找行为

这在 jOOQ 中绝对值得关注:

  • #12470 更好的 Javadoc
  • #12471 当用户尝试查找不受支持的class 文字时记录警告

如何解决?

在您的特定情况下,您已经在 LOG.OLD_VALUES 中引用了 DataType<JsonElement>。您的转换可以工作,但更好的是,只需完全删除 JsonElement.class 文字并改为编写:

// Assuming your JSON library is Gson
val(new JsonObject(), LOG.OLD_VALUES)

这将从 OLD_VALUES 列(包括其绑定)中获取 DataType,并使用它来绑定 JsonObject 值。