2017-05-25 64 views
0

我有一个DocumentJob表,其中包含要针对给定文档执行的作业。表中的每一行都有jobId,documentId和jobstatus。确保单个添加到SQL表中

多线程/进程将试图在任何给定的时间添加到此表(使用下面给出的代码)

begin tran 
if exists 
(
    select 1 from DocumentJob 
    where DocumentId = @inDocumentId 
    and Status in ('Running', 'New') 
) 
    throw 50001, 'New or Active Job for Document is already present', 1 

insert into DocumentJob (DocumentId, Status) values(DocumentId, 'New') 
select @JobId = scope_identity(); 
commit; 

对于给定的文档ID - 我想补充一个新的工作只有在没有任何其他工作正在运行或新的文档。以下代码片段是否处理上述要求,或者是否存在可能违反上述条件的一些条件?

我的目标是了解当上面的过程同时被调用时,表是否被正确锁定等。

+1

你有没有试过运行这段代码? – Tushar

+0

是的 - 添加等工作正常。我担心的是当同时调用proc时可能发生的竞争状况。 – shekhar

+1

我意识到我的描述不清晰并更新了它。 – shekhar

回答

1

[1] 的第一件事我会做的是,从而创建一个独特筛选索引:

CREATE UNIQUE NONCLUSTERED INDEX IUF_DocumentJob_DocumentId 
ON dbo.DocumentJob (DocumentId) 
--INCLUDE (...) 
WHERE Status in ('Running', 'New') 

这种独特的索引保证dbo.DocumentJob table'll有具有以下状态之一的唯一DocumentId小号:'Running''New'

这足以防止在状态为'Running''New'时出现重复的dbo.DocumentJob

[2] [1]中,包括在当前问题后,将源代码可以由一个简单的

INSERT INTO dbo.DocumentJob (DocumentId, Status) VALUES (@DocumentId, 'New') 

对于任何{@DocumentId值和RunningNew状态}仅第一INSERT(或UPDATE代替)执行会成功,下一次执行将失败。

注意:我会在交易(参见SET XACT_ABORT ON)和TRY ... CATCH块内封装此代码(此主题未在此答案中提供)。

[3]为了测试我就从微软使用ostress.exe工具(http://sqlmag.com/t-sql/2-tools-keep-sql-server-tuned)和/或以下办法

[3.1]在SSMS打开一个新的查询([新查询])窗口,并执行下面的代码

BEGIN TRAN 
    -- Replace 1234 with a new DocumentId 
    INSERT INTO dbo.DocumentJob (DocumentId, Status) VALUES (1234, 'New') 
-- COMMIT 

[3.2]内SSMS打开另一个查询([新查询])窗口,并执行下面的代码

BEGIN TRAN 
    -- Use the same DocumentId 
    INSERT INTO dbo.DocumentJob (DocumentId, Status) VALUES (1234, 'New') 
COMMIT 

[3.3]首先INSERT将成功,第二次将失败。

注意:如果您有任何问题(关于此答案),请询问。注2:不要忘记COMMIT(或ROLLBACK第一个Tx)。

+1

哇!真棒回答。让我试试这个。谢谢 ! – shekhar

相关问题