使用Knex的onConflict().merge()为何导致数据库产生重复行?
问题排查与解决
你遇到的重复插入问题,大概率是两个核心原因导致的:
1. 字段名不匹配
你的代码中,insert里用的是one_Id和twoId(驼峰+下划线混合命名),但onConflict指定的冲突判定字段是['one_id', 'two_id'](全下划线命名)。如果你的数据库字段是标准下划线命名,Knex处理字段名时会出现不匹配,导致冲突判定逻辑根本没触发——数据库会认为每次插入的都是新记录,自然不会执行更新操作。
修正代码,统一字段命名:
if (question.image_url) { // Update url if existing, otherwise create a new one await knex('table_getting_duplicated') .insert({ one_id: oneId, two_id: twoId, image_url: question.image_url }) .onConflict(['one_id', 'two_id']) .merge({ image_url: question.image_url }); }
2. 缺少联合唯一约束
onConflict().merge()生效的前提是,数据库表对指定的one_id和two_id存在联合唯一约束,否则数据库不会认为这两个字段的组合重复是冲突,只会直接插入新记录。
检查并创建约束
先查询表是否已有对应约束:
SELECT * FROM information_schema.table_constraints WHERE table_name = 'table_getting_duplicated' AND constraint_type = 'UNIQUE';
如果没有,执行SQL创建联合唯一约束:
ALTER TABLE table_getting_duplicated ADD CONSTRAINT unique_one_two_pair UNIQUE (one_id, two_id);
也可以用Knex迁移文件创建(推荐):
exports.up = function(knex) { return knex.schema.table('table_getting_duplicated', table => { table.unique(['one_id', 'two_id']); }); }; exports.down = function(knex) { return knex.schema.table('table_getting_duplicated', table => { table.dropUnique(['one_id', 'two_id']); }); };
额外排查点
循环执行时,确认每次迭代的oneId和twoId是当前问题对应的正确值,没有被错误复用之前循环的变量。
内容的提问来源于stack exchange,提问作者Jimmy Blundell
相关产品推荐
相关产品推荐

