用于更新的MS SQL锁定

用于更新的MS SQL锁定,sql,sql-server,tsql,Sql,Sql Server,Tsql,我正在实施一项竞赛,可能会有很多同时参赛的作品。我正在收集一些用户数据,并将其放入一个名为entries的表中。在一个名为折扣代码的表中,我有另一个预先生成的唯一折扣代码表。然后我为每个条目分配一个。我想我可以通过在折扣代码表中输入一个条目id来实现这一点 由于可能有很多并发用户,我认为应该选择第一个未分配的行,然后将条目id分配给该行。我需要确保在选择一个未分配的行和添加条目id之间,另一个线程找不到相同的行 确保行不会被分配两次的最佳方法是什么?我建议构建一个桥接表,而不是在折扣代码表中使用

我正在实施一项竞赛,可能会有很多同时参赛的作品。我正在收集一些用户数据,并将其放入一个名为entries的表中。在一个名为折扣代码的表中,我有另一个预先生成的唯一折扣代码表。然后我为每个条目分配一个。我想我可以通过在折扣代码表中输入一个条目id来实现这一点

由于可能有很多并发用户,我认为应该选择第一个未分配的行,然后将条目id分配给该行。我需要确保在选择一个未分配的行和添加条目id之间,另一个线程找不到相同的行


确保行不会被分配两次的最佳方法是什么?

我建议构建一个桥接表,而不是在
折扣代码
表中使用
EntryId
折扣代码ID
。在这两个字段上放置一个
唯一约束

WITH    e AS
        (
        SELECT  *,
                ROW_NUMBER() OVER (ORDER BY id) rn
        FROM    entries ei
        WHERE   NOT EXISTS
                (
                SELECT  NULL
                FROM    discountCodes dci
                WHERE   dci.entryId = ei.id
                )
        ),
        dc AS
        (
        SELECT  *,
                ROW_NUMBER() OVER (ORDER BY id) rn
        FROM    discountCodes
        WHERE   entryId IS NULL
        )
UPDATE  dc
SET     dc.entryId = e.id
FROM    e
JOIN    dc
ON      dc.rn = e.rn

这样,您的入口点在尝试输入副本时将遇到约束冲突。

可以执行以下操作:

以下示例设置会话的事务隔离级别。对于后面的每个Transact-SQL语句,SQL Server将保留所有共享锁,直到事务结束来源:MSDN

USE databaseName;
GO
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
GO
BEGIN TRANSACTION;
GO
SELECT * 
    FROM Table1;
GO
SELECT * 
    FROM Table2;
GO
COMMIT TRANSACTION;
GO

阅读更多内容

我只需在每个表上放置一个
标识
字段,并让相应的条目与相应的折扣代码匹配-即,如果您有1000个折扣代码,折扣代码表中的标识列的范围为1到1000。这将匹配您的第一个1到1000个条目。如果您收到的条目超过1000条,只需为每个附加条目添加一个折扣代码

通过这种方式,SQL Server可以为您处理所有有问题的“获取序列中的下一个数字”逻辑。

您可以尝试使用并同步写入操作,只需确保它针对相同的哈希锁定,如

DECLARE @state    Int

BEGIN TRAN

-- here we're using 1 sec's as time out, but you should determine what the min value is for your instance
EXEC @state = sp_getapplock 'SyncIt', 'Exclusive', 'Transaction', 1000

-- do insert/update/etc...

-- if you like you can be a little verbose and explicit, otherwise line below shouldn't be needed
EXEC sp_releaseapplock 'SyncIt', 'Transaction'

COMMIT TRAN

你能在表格中添加一个
falg
,这样你就可以在每一行选择一个标记吗?@huMptyduMpty问题是如果用户同时选择它,在设置标志之前,他们可以选择相同的折扣代码。@Elias:是的,但您可以避免使用同一行两次?请参阅。您不能在存储用户数据的位置生成折扣代码,而不是预生成折扣代码?为什么要为此建一个桥接表?您也可以在现有的
discountCodes.entryId
上创建一个唯一的索引(实际上无论如何都应该这样做)。@Quassnoi
discountCodes
是更新的,而不是插入的,因为表是预先填充的。您的解决方案不会阻止
折扣代码。EntryId
被覆盖,即被使用两次。
标识
不保证是连续的。@Quassnoi这很有趣,除非您要删除一条记录,或声明您的标识以1以外的任何方式递增,或以任何方式摆弄它,在什么情况下,标识不能是连续的?除非您有意将增量设置为1以外的值,或者从表中删除行。@DanWierenga-不,不是。另一个常见原因是回卷插入件。在SQL Server 2012上,重新启动该服务也会留下很大的缺口。@Martin Smith-哇,我从来没有注意到回滚会增加标识计数器。很高兴知道,谢谢!这会自动锁定吗?也就是说,如果您同时运行选择和更新,另一个线程是否也可以在选择和运行更新之间选择同一行?@SteveTemple:会。只要另一个会话尝试读取已更新但尚未提交的
折扣代码
记录(这是
不存在
部分所要求的),它就会被锁定。