我正在启动一个项目,我需要确保大量用户可以获得多个促销活动的促销代码。
代码附有货币价值,因此每个用户只能输出一个代码,而且没有两个用户可以接收代码,这一点至关重要。
到目前为止,我的计划是在SQL Server中创建一个名为code_pool
的表,并且每次都会批量插入代码。
SQL Server 2005表看起来像这样......
[id](int pk), [promo_code] varchar(150), [promotion_id](int fk)
然后,用户将使用存储过程来检索每个代码,该过程将从该表中获取该促销的第一条记录,然后在作为过程结果返回代码之前删除(或更新)记录。
我的问题是如何确保记录被正确锁定,以便只有一个用户可以获得每个记录,并且没有两个用户同时访问proc会收到相同的代码?
我是否需要锁定表/记录,如果是这样,它将如何在繁忙的生产环境中堆叠?
答案 0 :(得分:2)
用于生成不易猜测的唯一代码的一种非常方便的内置数据类型是uniqueidentifier
数据类型。您可以使用它来生成唯一代码,方法是使其具有自动生成的值(使用newid()函数)。由于GUID是HEX并且不像标识列那样按顺序生成,因此无法预测已生成或将生成的代码,这将使您的流程不再容易受到依次尝试代码的人的攻击。可能的uniqueidentifier数量非常大。
我已经假设每个宣传片每个人只需要一个促销代码。你在数据库中这样做的方法是通过一个表,我的例子称之为PromoTest,它在这两列上都有一个主键,这将确保它们保持唯一。我没有添加“使用”的概念来表明该人是否使用过该代码,但这样做非常简单。
要使用主键约束和自动生成的值创建表,请运行以下命令:
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
答案 1 :(得分:1)
你不想添加一个列,例如in_use(int)?当你生成新的promocode时,in_use = 0,当你的存储过程获得未使用的促销代码时,它选择第一个代码,其中in_use = 0,然后将其更新为1
答案 2 :(得分:0)
为什么不使用类似的东西,但是这样:
Table UsedCodes
[id] int identity PK,
[userId] whatever,
[PromoId] int FK
Table Promotions
[PromoId] int pk,
[PromoCode] nvarchar
当用户获得促销代码时,您会在已使用的代码中插入一个值,并且提供给它们的促销代码将是促销代码与使用代码表中的ID的串联。
然后,您还可以对UserId |强制执行唯一约束使用代码表上的PromoId,以确保每个用户每个促销只有一个代码。
这样做的好处是可以保留所使用代码的记录,并降低需要批量插入的复杂性,这可能会意外地引入重复数据。它还具有无需锁定的优点......
答案 3 :(得分:0)
John P给了你一个很好的答案,但由于字符串的长度,我发现GUID很难用作代金券代码。
查看问题how to generate a voucher code in c#?,当然还有我的回答:)虽然您要求SQL解决方案,但您可以调整其中的想法。
我还建议您不要删除已使用的代码;您如何确定客户提供的代码是由您的系统创建的?