使用UpdatableRecord
的批量语句
如果你想要使用DSLContext.batchUpdate()
的便利性,而不必先从数据库中获取所有记录,则仍然可以使用UpdatableRecord
。假设你正在使用代码生成器,并且正在生成记录,则将拥有BalanceRecord
:
ctx.batchUpdate(balances
.stream()
.map(b -> {
var r = new BalanceRecord();
r.setAmount(b.getAmount());
r.setId(b.getId());
r.changed(BALANCE.ID, false);
return r;
})
.collect(toList()))
.execute();
这将为您在幕后创建一个批处理语句。
使用BatchedConnection
从 jOOQ 3.14 开始,您可以使用BatchedConnection
透明地批处理所有逻辑,它是一个特殊的 JDBC 连接代理,延迟执行所有 JDBC 语句(无论是 jOOQ 创建还是其他),并将它们缓冲直到需要执行:
dslContext.batched(c -> {
for (Balance balance : balances) {
c.dsl().update(BALANCE)
.set(BALANCE.AMOUNT, balance.getAmount())
.where(BALANCE.ID.eq(balance.getId))
.execute();
}
}
运行单个批量语句
从您的评论中,似乎希望将此作为单个批量语句运行,而不是在单个批量语句(单次往返)中批处理多个语句。
我并不确定这是否是正确的方法 - 语句可能会变得非常庞大,并不一定比批处理更快,但当然,您可以使用CASE
表达式来实现这一点。
ctx.update(BALANCE)
.set(BALANCE.AMOUNT,
case_(BALANCE.ID).mapValues(
balances.stream().collect(toMap(balance::getId, balance::getValue))
)
)
.where(BALANCE.ID.in(balances.stream().map(balance::getId).collect(toList())))
.execute();
这将产生类似下面的内容:
UPDATE balance
SET amount =
CASE id
WHEN 1 THEN 2.50
WHEN 2 THEN 3.50
WHEN 13 THEN 8.30
END
WHERE id IN (1, 2, 13)
根据你使用的方言,这可能更适合使用MERGE
来完成:
MERGE INTO balance
USING (
VALUES (1, 2.50), (2, 3.50), (13, 8.30)
) AS s (i, b)
ON balance.id = s.i
AND balance.balance = s.b
WHEN MATCHED THEN UPDATE SET balance = b
(id, amount)
对是从哪里来的? - Lukas Eder