使用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); // Prevent setting the ID to itself
return r;
})
.collect(toList()))
.execute();
这将为您在幕后创建一个batch statement。
使用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(); // This doesn't execute the query yet
}
} // Now, the buffered queries are being batch-executed
运行单个批量语句
从您的 cmets 看来,似乎希望将其作为单个 bulk 语句 运行,而不是在单个 batch 语句 中批处理多个语句(单次往返)。
我不相信这是正确的方法 - 语句可能会变得很大并且不一定比批处理快,但当然,您可以使用 CASE expression 来做到这一点
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