0

我有一个许可证密钥/序列号的 sql server 表。表结构类似于;

[
RecordId int,
LicenceKey string,
Status int (available, locked, used, expired etc.)
AssignedTo int (customerId)
....
]

通过我的 ASP.NET 应用程序,当用户决定单击接受按钮购买许可证时,我需要为用户保留许可证密钥。我的方法是,从 KeysTable 中选择前 1 个许可证密钥,其中状态 = 可用更新密钥表设置状态 = 锁定,然后将密钥返回给应用程序。

我担心的是,如果两个 asp.net 线程访问相同的记录并返回相同的许可证密钥。您认为完成此类作业的最佳做法是什么?这类问题是否有众所周知的方法或模式?如果我需要,在哪里使用 lock() 语句?

我正在使用 Sql Server 2005、用于数据访问的存储过程、DataLayer、BusinessLayer 和 Asp.Net GUI。

谢谢

4

4 回答 4

4

在这种情况下,可能不需要使用显式锁或事务。

OUTPUT在您的存储过程中,您可以使用语句中的子句在单个原子操作中更新表并检索许可证密钥UPDATE

像这样的东西:

UPDATE TOP (1) KeysTable
SET Status = 'locked'
OUTPUT INSERTED.LicenseKey
-- if you want more than one column...
-- OUTPUT INSERTED.RecordID, INSERTED.LicenseKey
-- if you want all columns...
-- OUTPUT INSERTED.*
WHERE Status = 'available'
于 2009-04-22T13:21:48.963 回答
1

为了实现您所说的,您需要使用可序列化的事务。为此,请遵循以下模式:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION

--Execute select
--Execute update

COMMIT TRANSACTION

但是,为什么你有一个包含所有可能的许可证密钥的表?为什么没有密钥生成算法,然后在用户购买时创建一个新密钥?

于 2009-04-22T12:55:06.123 回答
0

我认为您实际上应该在您查询它的同一个存储过程中将密钥标记为不可用,因为否则总会有某种竞争条件。恕我直言,手动锁定表不是一个好习惯。

如果您有一个两阶段的过程(例如预订机票),您可以引入在指定时间段(例如 30 分钟)内保留密钥的概念,这样当您查询新密钥时,您可以在同时。

编辑:如果您可以保证只有一个进程会更改数据库,那么锁定业务逻辑可能会起作用,但最好在数据库级别进行,最好在单个存储过程中进行。要正确执行此操作,您必须设置事务级别并使用数据库中的事务,正如@Adam Robinson 在他的回答中所建议的那样。

于 2009-04-22T12:54:45.643 回答
0

除了事务之外,您还可以尝试使用锁(在 SQL 中)来验证一次只有一个线程可以访问。

我相信应用程序锁在这里可能会有所帮助。

于 2009-04-22T13:03:39.287 回答