smac89
smac89

Reputation: 43206

Jooq batch update with records in MySql

What is the proper way to do batch updates with JOOQ?

I have the following:

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();
    });
}

Which of these is the recommended way to do batch updates?

Upvotes: 1

Views: 3613

Answers (1)

Lukas Eder
Lukas Eder

Reputation: 221145

This question is obviously very subjective and not easy to answer. Here are a few observations:

  • Even with using the batch API in jOOQ, you're running a lot of individual queries, which incurs quite a bit of client/server overhead. This might be fine in your particular case, but it's usually not a bad idea to consider moving the entire logic into the database, e.g. by inserting your map in a temporary table and then merging the two data sets using a bulk UPDATE statement
  • Both of your batches may cause deadlocks in the database, if two conflicting batches update the same records in a different order. I'm not sure if this is an issue in your code, but you may want to make sure this can never happen.
  • The first approach will run one less query (the SELECT query, which might be quite expensive, depending on the size of the in-list). Without the FOR UPDATE clause, however, the first approach might have a higher deadlocking risk.
  • The first approach will potentially run more update statements than necessary, e.g. for ID values that have been deleted in the meantime. The second approach prevents that from happening

Now, I don't know MySQL well enough to know if a bulk update statement might be better here, i.e. a statement of the kind:

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, ...)

Perhaps you could benchmark this approach and compare it to batching (or combine it with batching, e.g. bulk update 10 rows and batch all these bulk updates)

Upvotes: 3

Related Questions