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 中绝对值得关注:
如何解决?
在您的特定情况下,您已经在 LOG.OLD_VALUES
中引用了 DataType<JsonElement>
。您的转换可以工作,但更好的是,只需完全删除 JsonElement.class
文字并改为编写:
// Assuming your JSON library is Gson
val(new JsonObject(), LOG.OLD_VALUES)
这将从 OLD_VALUES
列(包括其绑定)中获取 DataType
,并使用它来绑定 JsonObject
值。
将我的 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 中绝对值得关注:
如何解决?
在您的特定情况下,您已经在 LOG.OLD_VALUES
中引用了 DataType<JsonElement>
。您的转换可以工作,但更好的是,只需完全删除 JsonElement.class
文字并改为编写:
// Assuming your JSON library is Gson
val(new JsonObject(), LOG.OLD_VALUES)
这将从 OLD_VALUES
列(包括其绑定)中获取 DataType
,并使用它来绑定 JsonObject
值。