当前位置: 首页 > 知识库问答 >
问题:

插入不存在但线程安全的位置(我不希望重复)

宦正诚
2023-03-14

如果具有匹配ID的值不存在,则需要将值插入表中,如以下线程中所示:SQL-insert Where not Exists

但是我需要确保如果另一个线程在完全相同的时间执行一个查询,我不会得到两个相同的行。

这是我的桌子:

CREATE TABLE [dbo].[Localizations]
(
    [id] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](50) NOT NULL,
    [regionId] [int] NOT NULL
) ON [PRIMARY]

这是我当前的查询,如果regionId=x的本地化行不存在,则会插入一个新的本地化行(不幸的是,它工作不正确-现在我的数据库中有重复项):

-- firstly I execute something like that (my real queries are more complex):    
DECLARE @id int = (SELECT [id] FROM [dbo].[Localizations] WHERE regionId = 1);
    
-- secondly I execute something like that (my real queries are more complex):
IF (@id IS NULL)
BEGIN
    INSERT INTO [dbo].[Localizations] 
    VALUES ('Test', 1);  
END

这导致现在我有许多行具有相同的regionId,我现在无法删除它们,它们在不同的表中使用:(:(:)因此,我无法在regionId列上创建唯一约束,因为我有重复项:(:(

如果多个线程同时执行该查询,您能告诉我以下查询是否不会创建具有相同regionId的重复项吗?我已经阅读了以下线程:SQL-Insert Where Not Exists,但我不确定,我不想插入更多重复的线程:(

INSERT INTO [dbo].[Localizations] (name, regionId)
    SELECT 'Test', 1
    WHERE NOT EXISTS (SELECT * 
                      FROM [dbo].[Localizations] 
                      WHERE regionId = 1)

共有2个答案

颛孙智勇
2023-03-14

您已经知道答案,应该删除重复项并添加唯一约束。在那之前,你的数据都会被破坏。

如果你只想要一个新数据的补丁,你可以在区域ID上创建唯一的过滤索引,在那里你可以过滤区域ID

云和硕
2023-03-14

删除重复项并添加唯一约束后,您可以更改批处理以防止会话尝试插入重复项,如下所示:

BEGIN TRANSACTION;
DECLARE @id int = (SELECT [id] FROM [dbo].[Localizations] WITH (UPDLOCK,HOLDLOCK) WHERE regionId = 1);
    
-- secondly I execute something like that (my real queries are more complex):
IF (@id is null)
BEGIN
    INSERT INTO [dbo].[Localizations] VALUES('Test', 1);  
END
COMMIT TRANSACTION;

这将强制第一个查询获取并保持行或空范围上的更新锁,这将确保插入成功,并且运行此代码的任何其他会话都将阻塞,直到提交事务为止。

 类似资料:
  • 扫描仪sc=新扫描仪(系统输入);字符串A=sc.nextLine();

  • 我想在我的Android应用程序中处理位图——位图可能很大,所以我使用多线程来执行更快的操作。以下是我的代码(Runnable child的一部分): 当我只使用池中的一个线程时,一切正常。不幸的是,当我使用的线程数等于处理器的内核数(在我的设备中为4)时,结果如下(对于灰度过滤器): 有时看起来像: bitmap.get像素(...)不起作用,因为输出中有黑线 bitmap.set像素(...)

  • 问题内容: 我正在编写一个将HashMap返回给用户的应用程序。用户将获得对此MAP的引用。在后端,我将运行一些线程来更新Map。 到目前为止我做了什么? 我已经使所有后端线程都共享一个公用通道来更新MAP。因此,在后端,我确信并发写入操作不会成为问题。 我遇到的问题 如果用户尝试更新MAP并同时在后端更新MAP->并发写入操作问题。 如果使用尝试从MAP读取某些内容,同时MAP正在后端更新->并

  • 在Java类的总体描述中,我遇到了这样一行:“然而,即使所有操作都是线程安全的,检索操作也不需要锁定,并且不支持以阻止所有访问的方式锁定整个表”。我的问题是:这是否意味着并发HasMap不能防止死锁?我还认为线程安全意味着不会发生死锁?

  • 我正在使用okhttp和Registfit调用REST服务。从服务返回数据存储在我的Android应用程序中的sqlite数据库中。

  • 在我的应用程序中,我使用多个线程来处理客户端连接。 我在调试时发现了一个非常奇怪的行为——我有一个SelectionKey,通过调用(使用调试器)它的interestTops()方法,返回值是1(READ),但当我将数据发送到与该键对应的套接字时,选择器不会被唤醒。。 如果使用调试器,我将特定选择键更改为1(即使是1),选择器会突然对该更改做出反应。 在给定的时间内,我只有一个线程处理一个连接,但