Jooq 批量更新 MySql 中的记录
Jooq batch update with records in MySql
使用 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();
});
}
或
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();
});
}
推荐使用以下哪种方式进行批量更新?
这个问题显然很主观,不好回答。以下是一些观察结果:
- 即使在 jOOQ 中使用批处理 API,您也会 运行 处理很多单独的查询,这会产生相当多的 client/server 开销。这在您的特定情况下可能没问题,但考虑将整个逻辑移入数据库通常不是一个坏主意,例如通过在临时 table 中插入地图,然后使用批量
UPDATE
语句 合并两个数据集
- 如果两个冲突的批次以不同的顺序更新相同的记录,那么您的两个批次都可能导致数据库死锁。我不确定这是否是您的代码中的问题,但您可能想确保这永远不会发生。
- 第一种方法将 运行 少一个查询(
SELECT
查询,这可能非常昂贵,具体取决于 in-list 的大小)。但是,如果没有 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 行并批处理所有这些批量更新)
使用 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();
});
}
或
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();
});
}
推荐使用以下哪种方式进行批量更新?
这个问题显然很主观,不好回答。以下是一些观察结果:
- 即使在 jOOQ 中使用批处理 API,您也会 运行 处理很多单独的查询,这会产生相当多的 client/server 开销。这在您的特定情况下可能没问题,但考虑将整个逻辑移入数据库通常不是一个坏主意,例如通过在临时 table 中插入地图,然后使用批量
UPDATE
语句 合并两个数据集
- 如果两个冲突的批次以不同的顺序更新相同的记录,那么您的两个批次都可能导致数据库死锁。我不确定这是否是您的代码中的问题,但您可能想确保这永远不会发生。
- 第一种方法将 运行 少一个查询(
SELECT
查询,这可能非常昂贵,具体取决于 in-list 的大小)。但是,如果没有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 行并批处理所有这些批量更新)