行并发问题多线程

时间:2014-08-25 19:20:09

标签: sql sql-server concurrency

我遇到并发问题。第三方软件正在执行我的存储过程,我需要在表中捕获唯一的ID列表。代码有效,直到多线程进入混合( gasp )。

我尝试了各种交易功能,包括隔离级别似乎无济于事。

基本上给出以下内容,我需要表'IDList'仅包含已发送的唯一ID。

当来自第三方软件的其他线程执行示例调用代码时,我始终以“IDList”中的重复项结束。我估计以下情况正在发生,但我无法解决:

  • 线程#1在insertMissingIDs
  • 中运行SELECT(带JOIN)
  • 线程#2在insertMissingIDs
  • 中运行SELECT(带JOIN)
  • 线程#1在insertMissingIDs
  • 中运行INSERT
  • 线程#2在insertMissingIDs
  • 中运行INSERT

结果:重复

我意识到这个例子可能看起来很愚蠢,我把它归结为不泄露机密代码。

致电代码:

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

提前致谢!

2 个答案:

答案 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

当然你也可能会受到阻碍。