And*_*ykh 5 sql-server concurrency sql-server-2014
这个说法:
INSERT INTO deleteme
SELECT #t.id, 'test' FROM #t
LEFT JOIN deleteme ON deleteme.id = #t.id
WHERE deleteme.id IS NULL;
Run Code Online (Sandbox Code Playgroud)
...将在并发场景中因主键冲突而失败(即,当同时从多个线程插入 deleteme 中不存在的相同键时),默认事务隔离级别为READ COMMITTED:
错误:违反 PRIMARY KEY 约束“PK_DeleteMe”。无法在对象“dbo.deleteme”中插入重复键。
防止这种情况的最佳方法是什么?
该表看起来像这样:
CREATE TABLE [dbo].[DeleteMe](
[id] [uniqueidentifier] NOT NULL,
[Value] [varchar](max) NULL,
CONSTRAINT [PK_DeleteMe] PRIMARY KEY ([id] ASC));
Run Code Online (Sandbox Code Playgroud)
更新
来自评论:
为什么你有多个会话,显然可以从某个地方提取相同的 id,使用相同的永久表而没有某种会话密钥来区分它们?即使没有重复错误,您如何知道哪些行属于哪个会话?
这是一个由填充此表中数据的外部服务调用的存储过程。该服务生成记录 ID,但不保证不会两次发送相同的数据。或者同时发送相同的数据。
数据库代码应该丢弃所有具有相同 id 的记录,如果一个记录已经存在。该服务绝不会在同一批次中发送两个具有相同 ID 的记录。
Aar*_*ron 10
如果您确实需要同时运行多个线程,您可以启用ignore_dup_key主键上的选项。
当插入会导致重复的键冲突时,这只会给出警告而不是错误。但它不会失败,而是丢弃如果插入会导致唯一性违规的行。
CREATE TABLE [dbo].[DeleteMe](
[id] [uniqueidentifier] NOT NULL,
[Value] [varchar](max) NULL,
CONSTRAINT [PK_DeleteMe]
PRIMARY KEY ([id] ASC)
WITH (IGNORE_DUP_KEY = ON));
Run Code Online (Sandbox Code Playgroud)
Paul White 关于 IGNORE_DUP_KEY 选项的详细解释。谢谢保罗。