jooq 在极少数情况下生成的 sql 不正确

Posted

技术标签:

【中文标题】jooq 在极少数情况下生成的 sql 不正确【英文标题】:Incorrect sql generated by jooq on rare occasions 【发布时间】:2021-06-26 10:00:53 【问题描述】:

我有一个 spring 云网关应用程序将身份验证数据保存到数据库。应用程序在 Kubernetes 中运行。我有太多不同的情况,有时我要保存 json 数据,而其他时候 json 数据为空。保存此数据的代码如下所示:

    with(AUTHENTICATED_SESSION) 
        context.insertInto(this, ACCESS_TOKEN_MD5_HASH, REFRESH_TOKEN, CONTEXT_DATA)
            .values(
                accessTokenMd5,
                refreshToken,
                if (contextData != null) 
                    JSONB.jsonb(objectMapper.writeValueAsString(contextData))
                 else 
                    null
                
            )
            .execute()
    

生成的列定义

public final TableField<AuthenticatedSessionRecord, JSONB> CONTEXT_DATA = createField(DSL.name("context_data"), SQLDataType.JSONB, this, "");

保存空值通常应该是这样的:

insert into "public"."authenticated_session" ("access_token_md5_hash", "refresh_token", "context_data") values (?, ?, cast(? as jsonb))
    : -> with bind values      : insert into "public"."authenticated_session" ("access_token_md5_hash", "refresh_token", "context_data") values ('hash', 'token', cast(null as jsonb))

有时查询看起来像这样,它会导致下面的异常

insert into "public"."authenticated_session" ("access_token_md5_hash", "refresh_token", "context_data") values (?, ?, ?)
    : -> with bind values      : insert into "public"."authenticated_session" ("access_token_md5_hash", "refresh_token", "context_data") values ('hash', 'token', null)
org.jooq.exception.DataAccessException: SQL [insert into "public"."authenticated_session" ("access_token_md5_hash", "refresh_token", "context_data") values (?, ?, ?)]; ERROR: column "context_data" is of type jsonb but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.
  Position: 121
    at org.jooq_3.14.6.DEFAULT.debug(Unknown Source) ~[na:na]
    at org.jooq.impl.Tools.translate(Tools.java:2880) ~[jooq-3.14.6.jar:na]
    at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:757) ~[jooq-3.14.6.jar:na]
    at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:389) ~[jooq-3.14.6.jar:na]
    at org.jooq.impl.AbstractDelegatingQuery.execute(AbstractDelegatingQuery.java:119) ~[jooq-3.14.6.jar:na]

因此,jooq 似乎在极少数情况下会生成不正确的 sql(没有强制转换为 jsonb)。

这个问题真的很烦人,因为发生这种情况时应用程序根本无法使用。重新启动 pod 会有所帮助。很可能只有在应用程序启动后才会出现此问题。

使用过的版本:

jooq 3.14.6 spring boot 2.3.5.RELEASE spring cloud gateway 2.2.5.RELEASE Docker 容器中的 Postgresql 10.12 postgresql 驱动程序 42.2.5 kotlin 1.4.10

【问题讨论】:

无关:由于 3.14.5 - 3.14.6 内存泄漏,请至少升级到 3.14.7:github.com/jOOQ/jOOQ/issues/11353 【参考方案1】:

你的问题中有提示,每次看到都非常高兴实现了这个功能:

 at org.jooq_3.14.6.DEFAULT.debug(Unknown Source) ~[na:na]

DEFAULT 指的是SQLDialect.DEFAULT,但在您的情况下应该是SQLDialect.POSTGRES。您收到无效 SQL 的原因是在这些情况下,您没有正确配置 Configuration

这应该可以帮助您找出问题所在,记住 jOOQ Query 对象不是线程安全的。

【讨论】:

很好,你能在源代码中生成它们的超链接位置吗?谢谢 @bedla.czech: github.com/jOOQ/jOOQ/blob/… 是的,确实是这个原因。在不配置方言的情况下,spring boot 尝试确定连接(并且在这些罕见的情况下失败):github.com/spring-projects/spring-boot/blob/master/… @Mikke:哦,有趣。你认为这个发现有错误吗?为什么有时它不起作用?当然,明确的方言总是更好,但省略它可能更方便...... @LukasEder 我没有理由相信发现中存在错误。我想我的问题是因为我们的开发环境。 CI 发布新镜像并将它们部署到 Kubernetes。很少有 db 容器在应用程序之前没有启动并导致发现失败。幸运的是,这不应该发生在 db 不在 kubernetes pod 中的生产环境中。

以上是关于jooq 在极少数情况下生成的 sql 不正确的主要内容,如果未能解决你的问题,请参考以下文章

Information_schema 未从 jooq for SQL Server 生成

是否有一个 jOOQ 工具来验证生成的定义是否仍然正确?

如何使用 jOOQ 通过 SQLite 正确生成日期和时间类型

如何在 jOOQ 中使用 formatJSON(JSONFormat) 正确格式化生成的 JSON 类型的常规结果?

jooq 和 java 8 流 SQL 生成

使用 DDL 数据库生成代码时找不到函数 - jooq