Jooq批量更新与MySql中的记录

时间:2018-04-04 20:26:05

标签: java mysql java-8 batch-processing jooq

使用JOOQ进行批量更新的正确方法是什么?

我有以下内容:

public void updateScores(Map<String, Integer> teamScores) {
    writeContext().transaction(config -> {
        DSLContext dslContext = DSL.using(config);
        dslContext.batchUpdate(Maps.transformEntries(teamScores, (id, score) -> {
            TeamScoresRecord record = new TeamScoresRecord();
            record.setTeamId(id);
            record.setScore(score);
            return record;
        }).values()).execute();
    });
}

OR

public void updateScores(Map<String, Integer> teamScores) {
    writeContext().transaction(config -> {
        DSLContext dslContext = DSL.using(config);
        dslContext.batchUpdate(
                dslContext.selectFrom(TEAM_SCORES)
                          .where(TEAM_SCORES.TEAM_ID.in(teamScores.keySet()))
                          .forUpdate()
                          .fetch()
                          .stream()
                          .peek(record -> record.setScore(teamScores.get(record.getTeamId())))
                          .collect(Collectors.toList())
        ).execute();
    });
}

推荐哪种方法进行批量更新?

1 个答案:

答案 0 :(得分:2)

这个问题显然非常主观,不容易回答。以下是一些观察结果:

  • 即使在jOOQ中使用批处理API,您也会运行大量单独的查询,这会产生相当多的客户端/服务器开销。在您的特定情况下这可能没问题,但考虑将整个逻辑移动到数据库中通常不是一个坏主意,例如将地图插入临时表,然后使用批量UPDATE语句合并这两个数据集
  • 如果两个冲突的批次以不同的顺序更新相同的记录,则两个批次都可能导致数据库死锁。我不确定这是否是您的代码中的问题,但您可能希望确保这种情况永远不会发生。
  • 第一种方法将运行少一个查询(SELECT查询,这可能非常昂贵,具体取决于列表中的大小)。但是,如果没有FOR UPDATE子句,第一种方法可能会有更高的死锁风险。
  • 第一种方法可能会运行比必要更多的更新语句,例如:对于在此期间已删除的ID值。第二种方法可以防止这种情况发生

现在,我不太清楚MySQL是否知道批量更新语句在这里是否更好,即类似声明:

UPDATE team_scores
SET score = CASE id
  WHEN :id1 THEN :score1
  WHEN :id2 THEN :score2
  WHEN :id3 THEN :score3
  ...
END
WHERE id IN (:id1, :id2, :id3, ...)

也许您可以对此方法进行基准测试并将其与批处理进行比较(或将其与批处理相结合,例如批量更新10行并批量处理所有这些批量更新)