有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Jooq批记录插入

我目前正试图批量插入许多记录(~2000条),而Jooq的batchInsert并不是我想要的

我将POJO转换为可更新记录,然后执行batchInsert,这是对每个记录执行insert。因此,Jooq对每个批插入进行了约2000次查询,这会降低数据库性能

它正在执行以下代码(jooq的批插入):

for (int i = 0; i < records.length; i++) {
            Configuration previous = ((AttachableInternal) records[i]).configuration();

            try {
                records[i].attach(local);
                executeAction(i);
            }
            catch (QueryCollectorSignal e) {
                Query query = e.getQuery();
                String sql = e.getSQL();

                // Aggregate executable queries by identical SQL
                if (query.isExecutable()) {
                    List<Query> list = queries.get(sql);

                    if (list == null) {
                        list = new ArrayList<Query>();
                        queries.put(sql, list);
                    }

                    list.add(query);
                }
            }
            finally {
                records[i].attach(previous);
            }
        }

我可以这样做(因为Jooq在内部也做同样的事情):

records.forEach(UpdatableRecord::insert);

而不是:

jooq.batchInsert(records).execute();

如何让Jooq以批处理模式创建新记录?我是否应该将记录转换为绑定查询,然后调用batchInsert?有什么想法吗?;)


共 (1) 个答案

  1. # 1 楼答案

    jOOQ的^{}使用相同的生成的SQL字符串为每组连续记录创建一个JDBC批处理语句(遗憾的是,Javadoc没有正式定义这一点)

    当您的记录如下所示时,这可能会变成一个问题:

    +   +    +    +
    | COL1 | COL2   | COL3   |
    +   +    +    +
    | 1*   | {null} | {null} |
    | 2*   | B*     | {null} |
    | 3*   | {null} | C*     |
    | 4*   | D*     | D*     |
    +   +    +    +
    

    。。因为在这种情况下,生成的SQL字符串将如下所示:

    INSERT INTO t (col1) VALUES (?);
    INSERT INTO t (col1, col2) VALUES (?, ?);
    INSERT INTO t (col1, col3) VALUES (?, ?);
    INSERT INTO t (col1, col2, col3) VALUES (?, ?, ?);
    

    这种违约行为的原因是,这是保证DEFAULT行为。就像SQL DEFAULTI gave a rationale of this behaviour here

    考虑到这一点,并且由于每个连续的SQL字符串都是不同的,很遗憾,插入并没有像您预期的那样作为单个批次进行批处理

    解决方案1:确保所有更改的标志都是true

    强制所有INSERT语句相同的一种方法是将每个单独记录的所有更改标志设置为true

    for (Record r : records)
        r.changed(true);
    

    现在,所有SQL字符串都将是相同的

    解决方案2:使用LoaderAPI

    您可以导入数据(并在其中指定批量大小),而不是批处理。有关详细信息,请参阅手册中有关导入记录的部分:

    https://www.jooq.org/doc/latest/manual/sql-execution/importing/importing-records

    解决方案3:改用批处理语句

    在使用batchInsert()时,使用TableRecords非常方便。当然,您可以手动生成INSERT语句,并使用jOOQ的批处理语句API批处理各个绑定变量:

    https://www.jooq.org/doc/latest/manual/sql-execution/batch-execution

    关于性能的说明

    关于DSLContext.batchInsert()和类似的API,有几个悬而未决的问题。为每个记录生成SQL字符串的客户端算法效率低下,将来可能会直接依赖changed()标志进行更改。一些相关问题: