我遇到并发问题。第三方软件正在执行我的存储过程,我需要在表中捕获唯一的ID列表。代码有效,直到多线程进入混合( gasp )。
我尝试了各种交易功能,包括隔离级别似乎无济于事。
基本上给出以下内容,我需要表'IDList'仅包含已发送的唯一ID。
当来自第三方软件的其他线程执行示例调用代码时,我始终以“IDList”中的重复项结束。我估计以下情况正在发生,但我无法解决:
结果:重复
我意识到这个例子可能看起来很愚蠢,我把它归结为不泄露机密代码。
致电代码:
DECLARE @ids IdType
INSERT INTO @ids
SELECT '123'
EXEC insertMissingIDs @ids
用户定义类型:
CREATE TYPE [dbo].[IdType] AS TABLE(
[ID] [nvarchar](250) NULL
)
步骤:
ALTER PROCEDURE [dbo].[insertMissingIDs]
@ids IdType READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO IDList (ID)
SELECT p.ID
FROM @ids i
LEFT JOIN IDList ON i.ID = IDList.ID
WHERE IDList.ID IS NULL
END
提前致谢!
答案 0 :(得分:1)
我认为你基本上有两个选择。您可以设置适当的事务隔离级别(文档here)。我认为使用set transaction isolation level serializable
可以解决问题。这可能会在您的交易中引入大开销。您将锁定表以进行读取和写入。一个电话必须等待前一个电话完成。在更复杂的情况下,您可能会陷入僵局。
另一种选择是使用IDLIST
选项定义主键表IGNORE_DUP_KEY
。这允许插入表中。如果要插入的数据中有重复项,则会忽略它们。
Here是一篇关于使用此选项的创造性方法的博文。
答案 1 :(得分:0)
首先,您应该在任何情况下在IDList(ID)
上放置一个唯一的密钥。这将保证不存在重复,但在上述并发进程的情况下,其中一个进程会收到错误。
如果要确保两个进程可以无错误地并发执行,那么将存储过程的隔离更改为可序列化并添加事务处理。
这样的事情应该有效:
ALTER PROCEDURE [dbo].[insertMissingIDs]
@ids IdType READONLY
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
Begin Transaction
INSERT INTO IDList (ID)
SELECT p.ID
FROM @ids i
LEFT JOIN IDList ON i.ID = IDList.ID
WHERE IDList.ID IS NULL
Commit Transaction
END
当然你也可能会受到阻碍。