SQL防止非重复的多个插入同时进行

时间:2017-04-05 05:30:21

标签: sql sql-server

我试图在同一时间阻止多次插入,这样我就可以防止重复插入。我有两张桌子:

  1. 表B中,此表格包含4列idtimeTokentokenOrdertaken

  2. 我将插入的表A包含idcreateDatetimeToken

  3. 我想要做的是防止表A中的timeToken在同一时间发生多个插入的情况下没有重复值。我有以下代码:

    DECLARE @ReturnValue nvarchar
    
    SELECT Top 1 @ReturnValue=timeToken FROM TableB WHERE taken = 0 Order By tokenOrder
    
    Update TableB SET taken = 1 WHERE timeToken = @ReturnValue
    
    INSERT INTO TableA Values(@ReturnValue, GETDATE())
    

    现在我考虑一下,是否可以使用TableB中的timeToken将TableA中的timeToken表自动增加?

    表B样本数据:

    id  timeToken   tokenOrder taken
    1   1:00am      1          0
    2   2:00am      2          0
    3   3:00am      3          1
    4   4:00am      4          0
    5   5:00am      5          0
    

    这就是我期望表A看起来像是在完全相同的4次调用之后会导致重复(id从5开始 - 这可能是因为我删除了旧记录)。

    表格A示例数据

    id     createDate                 timeToken
    5      2014-11-22 12:45:34.243    1:00am
    6      2014-11-22 12:45:34.243    2:00am
    7      2014-11-22 12:45:34.243    4:00am
    8      2014-11-22 12:45:34.243    5:00am
    

2 个答案:

答案 0 :(得分:1)

尝试像这样重写,这应该确保你不会让TableB中的if(mapkey.equalsIgnorCase("Donhawmun")) { ...... } else if(mapkey.equalsIgnorCase("Geumcheongyo")) { .... } 行更新两次。

taken=0

SQL Server isolation levels - 读取提交。 READ COMMITTED是Microsoft SQL Server数据库引擎的默认隔离级别。

在示例中,我将id从TableB复制到TableA,但可能不是必需的。

答案 1 :(得分:0)

我认为你可以分两步解决这个问题:

第1步:在所有请求到达后立即缓冲。

第2步:定期将自由令牌分配给缓冲的请求。

<强>制备

sequence对象有助于解决任何订单歧义:

CREATE SEQUENCE dbo.Taken_Seq  
    START WITH 1  
    INCREMENT BY 1 ;  
GO

辅助表将扮演缓冲区的角色:

CREATE TABLE buffer (
    requester uniqueidentifier, createdate datetime, seq_value bigint, id int);

我还将使用GUID来引用要求令牌(请求者)的不同进程:

ALTER TABLE TableA add Requester uniqueidentifier;

解决方案大纲

一旦请求(由GUID标识)缓冲区消耗下一个序列值,就像这样(这里我使用newid()获取GUID,您的应用程序应该已经为您的请求分配了一个):< / p>

declare @seq bigint;

SELECT @seq = NEXT VALUE FOR dbo.Taken_Seq;
insert buffer values (newid(), getdate(), @seq, null);

现在假设有三个这样的请求同时到达,如:

declare @seq bigint;

SELECT @seq = NEXT VALUE FOR dbo.Taken_Seq;
insert buffer values (newid(), getdate(), @seq, null);

SELECT @seq = NEXT VALUE FOR dbo.Taken_Seq;
insert buffer values (newid(), getdate(), @seq, null);

SELECT @seq = NEXT VALUE FOR dbo.Taken_Seq;
insert buffer values (newid(), getdate(), @seq, null);

buffer表的内容将如下所示:

requester                            createdate              seq_value            id
------------------------------------ ----------------------- -------------------- -----------
109B560C-155C-40BD-A13A-59D21EBEB1F8 2017-04-05 11:17:35.127 31                   NULL
FAC00C2E-14AA-4502-AB5C-DDD756914653 2017-04-05 11:17:35.127 32                   NULL
E95889C3-E291-4A1C-A7E8-0B8CC53D4D7B 2017-04-05 11:17:35.127 33                   NULL

接下来,我们可以将每个缓冲的请求与令牌进行匹配。这将通过为我们的缓冲表中的每个请求分配id值来完成:

; with a as 
(select rn =row_number() over (order by seq_value), *
from buffer 
where id is null), 
b as
(
select rn=row_number() over (order by tokenOrder), *
from TableB 
where taken = 0
)
update buffer set buffer.id = b.id 
from buffer 
join a on buffer.requester = a.requester 
join b on a.rn = b.rn

现在我们的buffer表格如下:

requester                            createdate              seq_value            id
------------------------------------ ----------------------- -------------------- -----------
109B560C-155C-40BD-A13A-59D21EBEB1F8 2017-04-05 11:17:35.127 31                   1
FAC00C2E-14AA-4502-AB5C-DDD756914653 2017-04-05 11:17:35.127 32                   2
E95889C3-E291-4A1C-A7E8-0B8CC53D4D7B 2017-04-05 11:17:35.127 33                   3

使用buffer加入TableB表格以查找令牌:

select buffer.requester, tableB.* from buffer join tableB on buffer.id= tableB.id

将标记标记为:

update TableB set taken = 1 from buffer where buffer.id = TableB.id

最后,插入TableA

insert TableA (requester, createdate, timeToken)
select buffer.requester, buffer.createdate, TableB.timeToken 
from buffer join TableB on buffer.id = TableB.id

注意: 显然,其中一些步骤必须包含在单个事务中