我正在实施一场可能有很多同时参赛的比赛。我正在收集一些用户数据,并将其放入一个名为条目的表中。我在一个名为 discountCodes 的表中有另一个预先生成的唯一折扣代码表。然后我为每个条目分配一个。我想我会通过在 discountCodes 表中放置一个条目 id 来做到这一点。
由于可能有很多并发用户,我认为我应该选择第一个未分配的行,然后将条目 ID 分配给该行。我需要确保在选择未分配的行和添加另一个线程找不到同一行的条目 id 之间。
确保该行不会被分配两次的最佳方法是什么?
我正在实施一场可能有很多同时参赛的比赛。我正在收集一些用户数据,并将其放入一个名为条目的表中。我在一个名为 discountCodes 的表中有另一个预先生成的唯一折扣代码表。然后我为每个条目分配一个。我想我会通过在 discountCodes 表中放置一个条目 id 来做到这一点。
由于可能有很多并发用户,我认为我应该选择第一个未分配的行,然后将条目 ID 分配给该行。我需要确保在选择未分配的行和添加另一个线程找不到同一行的条目 id 之间。
确保该行不会被分配两次的最佳方法是什么?
我建议构建一个桥接表,而不是EntryId
在DiscountCodes
表中使用 anEntryId
和 a DiscountCodeId
。Unique Constraint
在这两个字段上放置一个。
这样,您的入口点在尝试输入重复项时将遇到约束冲突。
可以做一些事情
以下示例设置会话的事务隔离级别。对于随后的每个 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
阅读更多设置交易隔离级别
您可以尝试使用sp_getapplock并同步写入操作,只需确保它锁定相同的哈希,例如
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
我只想IDENTITY
在每个表上放置一个字段,并让相应的条目与相应的 discountCode 相匹配 - 即,如果您预先有一千个 discountCodes,您在 discountCodes 表中的标识列的范围为 1 到 1000。这将匹配您的第一个 1 到1000 个条目。如果您获得超过 1000 个条目,只需为每个额外条目添加一个 discountCode。
这样,SQL Server 就会为您处理所有有问题的“获取序列中的下一个数字”逻辑。
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