2

我有以下脚本:

BEGIN
    IF NOT EXISTS (SELECT SessionID FROM SessionData WHERE SessionID = @SessionID)
    BEGIN
    SELECT @RegionID = RegionID
    FROM Region
    WHERE Domain = @Domain
    INSERT INTO SessionData (
    SessionID,
    SystemID,
    RegionID,
    RegionDomain,
    RemoteAddr,
    CreatePage)
    VALUES (
    @SessionID,
    @SystemID,
    @RegionID,
    @RegionDomain,
    @RemoteAddr,
    @CreatePage)
END
END

该网站有时会产生如下错误:

违反主键约束“PK_SessionData”。无法在对象“sbuser.SessionData”中插入重复键。重复的键值为 (1h6l61h069srw1nmw73j)。来源:Microsoft OLE DB Provider for SQL Server 编号:-2147217873

为什么它运行脚本,如果有一个重复的键..?我很困惑..任何帮助将不胜感激。

非常感谢..

4

2 回答 2

4

两个并发的重叠进程都将通过 NOT EXISTS 检查并尝试插入。

也就是说,NOT EXISTS 是对 INSERT 的单独查询

NOT EXISTS 和 INSERT 都可以写入单个 MERGE

MERGE INTO
    SessionData WITH (SERIALIZABLE) S
USING (
    SELECT
        @SessionID AS SessionID ,
        @SystemID AS SystemID ,
        RegionID,
        @RegionDomain AS RegionDomain ,
        @RemoteAddr AS RemoteAddr ,
        @CreatePage AS CreatePage 
    FROM Region
    WHERE Domain = @Domain
    ) src ON S.SessionID = src.SessionID
WHEN NOT MATCHED THEN
   INSERT (
       SessionID,
       SystemID,
       RegionID,
       RegionDomain,
       RemoteAddr,
       CreatePage)
    VALUES (
       src.SessionID,
       src.SystemID,
       src.RegionID,
       src.RegionDomain,
       src.RemoteAddr,
       src.CreatePage);
于 2013-07-12T12:26:16.397 回答
-1

这个怎么样:

INSERT INTO SessionData (
   SessionID,
   SystemID,
   RegionID,
   RegionDomain,
   RemoteAddr,
   CreatePage)
SELECT
   @SessionID,
   @SystemID,
   (SELECT TOP 1 RegionID FROM Region WHERE Domain = @Domain),
   @RegionDomain,
   @RemoteAddr,
   @CreatePage)
WHERE
   NOT EXISTS (SELECT SessionID FROM SessionData WITH (UPDLOCK, HOLDLOCK) 
                                WHERE SessionID = @SessionID)

这是一种无需任何 MERGE 或事务即可获得原子操作的简洁方法。

于 2013-07-12T13:42:08.183 回答