如何使用jooq更新插入记录?

How to Upsert records with jooq?

提问人:kocakmo 提问时间:11/5/2023 最后编辑:kocakmo 更新时间:11/6/2023 访问量:61

问:

我正在尝试将从数据库的一个表中检索到的行更新插入到另一个数据库中的相同表。这两个数据库都是 postgresql。

我只想将表行的整列作为记录检索,然后简单地将其更新插入到另一个数据库中的表中。

我写了以下代码:

try {
            String sourceDbUrl = "jdbc:postgresql://localhost:5432/sourcedb";
            String sourceDbUsername = "postgres";
            String sourceDbPassword = "admin";
            Connection sourceConnection = DriverManager.getConnection(sourceDbUrl, sourceDbUsername, sourceDbPassword);
            Configuration sourceConfig = new DefaultConfiguration().set(sourceConnection).set(SQLDialect.POSTGRES);


            String targetDbUrl = "jdbc:postgresql://localhost:5432/targetdb";
            String targetDbUsername = "postgres";
            String targetDbPassword = "admin";
            Connection targetConnection = DriverManager.getConnection(targetDbUrl, targetDbUsername, targetDbPassword);
            Configuration targetConfig = new DefaultConfiguration().set(targetConnection).set(SQLDialect.POSTGRES);

            String sourceSchema = "public";
            String targetSchema = "public";

            Table<Record> sourceTable = DSL.table(DSL.name(sourceSchema, "mytable"));
            Table<Record> targetTable = DSL.table(DSL.name(targetSchema, "mytable"));
            DSLContext sourceDslContext = DSL.using(sourceConfig);
            DSLContext targetDslContext = DSL.using(targetConfig);
            String customSelectQuery = "SELECT * FROM " + sourceSchema + ".mytable";

            Result<Record> records = sourceDslContext.fetch(customSelectQuery);
            
            for (Record record : records)
                targetDslContext
                        .insertInto(targetTable)
                        .set(record)
                        .onDuplicateKeyUpdate()
                        .set(record)
                        .execute();


        } catch (Exception e) {
            e.printStackTrace();
        }

我可以看到我已成功检索记录。

但是,不知何故,记录值在 for 循环中由 jooq 创建的 upsert 查询中为空,我得到了以下异常:

org.jooq.exception.DataAccessException:SQL [插入到“public”中。mytable“ 值 () on conflict ([unknown primary key]) do update set [ no fields are updated ]];ERROR:在“)”处或附近出现语法错误 排名:40 在 org.jooq_3.16.1.POSTGRES.debug(来源不明) 在org.jooq.impl.Tools.translate(Tools.java:3089) 在 org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:670) 在org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:349) 在 org.jooq.impl.AbstractDelegatingQuery.execute(AbstractDelegatingQuery.java:115) 在 Main.main(Main.java:48) 原因:org.postgresql.util.PSQLException:错误:语法错误在“)”或附近 排名:40 在 org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2552) 在 org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2284) 在 org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:322) 在 org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:481) 在 org.postgresql.jdbc.PgStatement.execute(PgStatement.java:401) 在 org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164) 在 org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:153) 在 org.jooq.tools.jdbc.DefaultPreparedStatement.execute(DefaultPreparedStatement.java:219) 在org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:414) 在 org.jooq.impl.AbstractDMLQuery.execute(AbstractDMLQuery.java:961) 在 org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:335) ...另外 2

感谢您的评论。

谢谢

java jooq upsert

评论


答:

0赞 Lukas Eder 11/6/2023 #1

这篇关于为什么应该使用 jOOQ 和代码生成的文章解释了为什么你会遇到这个问题。简而言之,如果没有附加到表的主/唯一键元数据,jOOQ 就无法在 PostgreSQL 方言上模拟 MySQL 子句。ON DUPLICATE KEY UPDATE

但话又说回来,为什么要使用它呢?您使用的是 PostgreSQL,并且 jOOQ 对 PostgreSQL 的子句(或者也适用于更复杂的情况)提供了本机支持,因此请改用本机语法。ON CONFLICTMERGE

评论

0赞 kocakmo 11/6/2023
嗨,卢卡斯,非常感谢您的回复。我的应用程序的角色是连接到数据库并检索新插入或更新的数据,并使用用户提供的表和数据库将其更新插入到目标数据库。这些东西可能是任何类型的表和数据库(刚开始使用 postgresql)。到目前为止,为了实现这一点,我需要通过jooq代码生成器将物理表与代码中的类相关联,以获取upsert操作的主键,对吗?由于从应用程序方面来看一切都是可以改变的,有什么方法可以不处理类吗?
0赞 Lukas Eder 11/6/2023
@kocakmo:我明白了。在这种情况下,仅当您使用 jOOQ 的代码生成器也使用的内部 API 来指定主键元数据时,这才有效。基本上,扩展 .由于不建议这样做或记录在案,因此我不会在这里展示一个示例。但这样做肯定是可能的。TableImpl