如何在JOOQ中实现batchMerge完成PostgreSQL批量upsert操作
问题根因
batchMerge默认使用表的主键作为冲突匹配条件,你的业务要求是用id+anotherId两个字段联合匹配,和默认主键规则不一致,所以只会插入新数据,不会触发已有匹配记录的更新。
实现方案
你使用的是PostgreSQL,推荐用原生支持的INSERT ON CONFLICT语法实现批量upsert,性能比通用merge语法更优,实现步骤如下:
- 先确保你的数据库item表上已经创建了
(id, anotherId)的联合唯一约束,SQL参考:
ALTER TABLE item ADD CONSTRAINT unique_id_anotherid UNIQUE (id, another_id);
- JOOQ批量upsert代码示例:
// 业务层传入的待处理Item列表 List<Item> items = ...; dslContext.batch( // 构造基础upsert语句 dslContext.insertInto(ITEM) .columns(ITEM.ID, ITEM.ANOTHER_ID, ITEM.THINGS) // 占位用的空值,后续批量绑定参数 .values((UUID) null, (UUID) null, (String[]) null) // 冲突匹配条件:id和anotherId同时匹配 .onConflict(ITEM.ID, ITEM.ANOTHER_ID) .doUpdate() // 冲突时更新非匹配字段,excluded指代插入的新值 .set(ITEM.THINGS, excluded(ITEM.THINGS)) // 如果有其他需要更新的字段,按上面格式补充即可 ) // 批量绑定所有Item的参数 .bind( items.stream() .map(item -> new Object[]{ item.getId(), item.getAnotherId(), item.getThings().toArray(new String[0]) }) .toArray(Object[][]::new) ) .execute();
可选batchMerge实现
如果你坚持要使用batchMerge方法实现,可以在构造每条ItemRecord时显式指定匹配键,代码示例如下:
List<ItemRecord> records = items.stream() .map(item -> { ItemRecord record = dslContext.newRecord(ITEM, item); // 显式指定联合匹配键 record.setKey(List.of(ITEM.ID, ITEM.ANOTHER_ID)); return record; }) .toList(); dslContext.batchMerge(records).execute();
内容的提问来源于stack exchange,提问作者EDR
相关产品推荐
相关产品推荐

