Database SQL Server获取唯一记录

Database SQL Server获取唯一记录,database,sql-server-2005,stored-procedures,locking,Database,Sql Server 2005,Stored Procedures,Locking,我正在启动一个项目,我需要确保大量用户可以获得多个促销的促销代码 这些代码附带有一个货币价值,因此每个用户只能收到一个代码,而任何两个用户都不能收到该代码,这一点至关重要 到目前为止,我的计划是在SQL Server中创建一个名为code\u pool的表,并每次大量插入代码 SQL Server 2005表将如下所示 [id](int pk), [promo_code] varchar(150), [promotion_id](int fk) 然后,用户将使用存储过程检索每个代码,该存储过程

我正在启动一个项目,我需要确保大量用户可以获得多个促销的促销代码

这些代码附带有一个货币价值,因此每个用户只能收到一个代码,而任何两个用户都不能收到该代码,这一点至关重要

到目前为止,我的计划是在SQL Server中创建一个名为
code\u pool
的表,并每次大量插入代码

SQL Server 2005表将如下所示

[id](int pk), [promo_code] varchar(150), [promotion_id](int fk)
然后,用户将使用存储过程检索每个代码,该存储过程将从表中获取该升级的第一条记录,然后删除(或更新)该记录,然后将代码作为过程的结果返回

我的问题是如何确保记录被正确锁定,以便只有一个用户可以获得每个记录,并且没有两个同时访问proc的用户会收到相同的代码


我是否需要锁定表/记录?如果需要,在繁忙的生产环境中这将如何累积

是否要添加一列,例如in_use(int)?生成新的促销代码时,在_use=0中,当存储的proc获取未使用的促销代码时,它会选择第一个在_use=0中的代码,然后将其更新为1,为什么不使用类似的代码,但如下所示:

Table UsedCodes
[id] int identity PK,
[userId] whatever,
[PromoId] int FK

Table Promotions
[PromoId] int pk,
[PromoCode] nvarchar
当用户获得促销代码时,您将在已用代码中插入一个值,并且传递给他们的促销代码将是促销代码和已用代码表中ID的串联

然后,您还可以在used codes表上对UserId | PromoId强制一个唯一的约束,以确保每个用户的每个promo只有一个代码


这样做的好处是保留所用代码的记录,并降低了需要批量插入的复杂性,这可能会意外引入DUP。它还具有不需要锁定的优点…

一种非常方便的内置数据类型,用于生成不易猜测的唯一代码,即
uniqueidentifier
数据类型。通过使其具有自动生成的值(使用newid()函数),可以使用该函数生成唯一的代码。因为guid是十六进制的,不像identity列那样是按顺序生成的,所以不可能预测已经生成或将生成哪些代码,这将使您的进程不易受到仅按顺序尝试代码的人的攻击。可能的唯一标识符的数量非常大

我假设你每个人只想要一个促销代码。在数据库中执行此操作的方法是使用一个表,我的示例称之为PromoTest,它在这两列上都有一个主键,这将确保它们保持唯一性。我没有添加“Used”的概念来表示此人是否使用了代码,但这很简单

要使用主键约束和自动生成的值创建表,请运行以下命令:

CREATE TABLE [dbo].[PromoTest](
[personid] [bigint] NOT NULL,   [promocategory] [int] NOT NULL, 
[promocode] [uniqueidentifier] NOT NULL,  
   CONSTRAINT [PK_PromoTest] PRIMARY KEY CLUSTERED  (   
         [personid] ASC,    
         [promocategory] ASC )
      WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS 
= ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] ) ON [PRIMARY]

GO

ALTER TABLE [dbo].[PromoTest] ADD  CONSTRAINT [DF_PromoTest_promocode]  DEFAULT (newid()) FOR [promocode]
然后让一个存储过程插入新的促销代码或选择现有的促销代码是非常简单的,并且由于主键约束,您不能为同一个人实际插入两个相同类型的代码

存储过程可以定义如下:

CREATE PROCEDURE GetOrCreatePromoCode 
    -- Add the parameters for the stored procedure here
    @PersonId bigint,
    @PromoCategory int, 
    @PromoCode uniqueidentifier OUT
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    IF (NOT EXISTS(SELECT PromoCode FROM PromoTest WHERE personid = @PersonId AND promocategory = @PromoCategory))
      BEGIN
        INSERT INTO PromoTest (personid, promocategory) VALUES (@PersonId, @PromoCategory)      
      END
    SET @PromoCode = (SELECT PromoCode FROM PromoTest WHERE personid = @PersonId AND promocategory = @PromoCategory)
END
GO
已经给了你一个很好的答案,但是我发现由于字符串长度的原因,guid很难用作凭证代码

看一看这个问题,当然我的答案是:)尽管您要求的是SQL解决方案,但您可能可以调整这里给出的想法

我还建议您不要删除已使用的代码;您如何确保客户提供的代码是由您的系统创建的