You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SQL Server中可靠插入不存在的记录?(多用户环境兼容)

跨数据库可靠初始化数据方案(避免唯一索引冲突)

一、用数据库原生语法杜绝竞态问题

别用「先查询再插入」的逻辑——这种方式在多用户/多实例并发启动时必然出现竞态,导致重复插入触发索引冲突。直接用数据库原生的冲突忽略语法,这些语法是原子操作,由数据库内核层面保证并发安全:

SQLite 实现

使用 INSERT OR IGNORE 语法,唯一索引冲突时自动跳过插入,不会抛出错误:

INSERT OR IGNORE INTO your_table (unique_col, col1, col2)
VALUES ('unique_value_1', 'val1', 'val2'),
       ('unique_value_2', 'val3', 'val4');

PostgreSQL 实现

使用 INSERT ON CONFLICT DO NOTHING 语法,可指定唯一索引对应的字段(复合索引或指定索引名称也支持):

INSERT INTO your_table (unique_col, col1, col2)
VALUES ('unique_value_1', 'val1', 'val2'),
       ('unique_value_2', 'val3', 'val4')
ON CONFLICT (unique_col) DO NOTHING;

如果是复合唯一索引,可写成 ON CONFLICT (col_a, col_b) DO NOTHING;也可通过索引名称指定:ON CONFLICT ON CONSTRAINT unique_index_name DO NOTHING。

二、事务锁的必要性说明

不需要额外手动设置事务锁,原因如下:

  1. 上述原生插入语句本身就是原子执行的,数据库会自动处理并发场景下的索引冲突,不会出现重复插入或报错。
  2. 如果需要批量插入多条初始化数据、或同时操作多张表,只需把语句放在普通事务中,确保初始化操作的原子性(要么全部完成,要么全部回滚)即可,无需加排他锁之类的特殊锁:
BEGIN TRANSACTION;
-- 这里放SQLite/PostgreSQL对应的插入语句
INSERT OR IGNORE INTO table1 (...) VALUES (...);
INSERT OR IGNORE INTO table2 (...) VALUES (...);
COMMIT;
  1. 完全兼容「应用运行期间数据可变更」的需求:这些语法只会跳过已存在的记录,不会修改任何现有数据,不会影响业务数据的正常修改。

为什么部分Stack Overflow方案会失效?

那些失效的方案大多采用「SELECT检查是否存在 → 不存在则INSERT」的拆分逻辑,这两步没有原子性保证,多进程并发时会出现两个进程都通过SELECT检查、同时执行INSERT的情况,最终触发唯一索引冲突。而原生冲突处理语法把「检查+插入」合并成一个原子操作,从根源上避免了竞态问题。

内容的提问来源于stack exchange,提问作者Igor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:22:39