确保单个添加到 SQL table

Ensuring single add into SQL table

我有一个 DocumentJob table,其中包含要针对给定文档执行的作业。 table 中的每一行都有 jobId、documentId 和 jobstatus。

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

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 - 我只想在 运行 或新文档没有其他作业的情况下添加新作业。以下代码片段是否满足上述要求,或者在某些情况下是否会违反上述条件?

我的objective是了解当同时调用上述过程时table是否会被正确锁定等。

[1] 我要做的第一件事 是创建一个唯一的过滤索引:

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

此唯一索引保证 dbo.DocumentJob table 将拥有一个具有以下状态之一的唯一 DocumentId'Running''New'

当状态为 'Running''New'.

时,这足以防止重复 dbo.DocumentJobs

[2] 在 [1] 之后,当前问题中包含的源代码可以替换为简单的

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

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

注意:我会将此代码封装在事务中(参见 SET XACT_ABORT ON),也会封装在 TRY ... CATCH 块中(此主题未在本答案中介绍)。

[3] 为了进行测试,我将使用 Microsoft (http://sqlmag.com/t-sql/2-tools-keep-sql-server-tuned) 的 ostress.exe 工具和/或以下方法

[3.1] 在 SSMS 中打开一个新查询([新查询])window 并执行以下代码

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

[3.2] 在 SSMS 中打开另一个查询([新查询])window 并执行以下代码

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

[3.3]第一个INSERT会成功,第二个会失败。

注意:如果您有任何问题(关于这个答案)请提问。 注意 2:不要忘记提交(或先回滚 Tx)。