2010-11-19 2 views
1

Я начинаю проект, где мне нужно убедиться, что большой объем пользователей может получить промо-код для нескольких рекламных акций.SQL Server получает уникальные записи

Коды имеют приложенную к ним денежную стоимость, поэтому жизненно важно, чтобы каждый пользователь обращался только к одному коду, и ни один из двух пользователей не может получить код.

Мой план до сих пор заключается в том, чтобы создать таблицу в SQL Server, известную как code_pool, и делать объемную вставку кодов каждый раз.

SQL Server 2005 таблицы будет выглядеть следующим образом ...

[id](int pk), [promo_code] varchar(150), [promotion_id](int fk) 

Пользователей затем извлечь каждый код с помощью хранимой процедуры, что бы получить первую запись из таблицы для этой акции, и затем удалить (или обновление) запись перед возвратом кода в результате процедуры.

Мой вопрос: как я могу обеспечить, чтобы запись была заблокирована так, чтобы только один пользователь мог когда-либо получать каждую запись и что ни один из двух пользователей, обращающихся к proc одновременно, никогда не получит один и тот же код?

Нужно ли блокировать стол/записи, и если да, то как это будет складываться в загруженной производственной среде?

ответ

1

Не хотите добавить столбец, например. in_use (int)? когда вы создаете новый промокод in_use = 0, когда ваш сохраненный proc получает неиспользованный промо-код, он выбирает первый код, где in_use = 0, а затем обновляет его до 1

0

Почему бы не использовать что-то подобное, но вот так:

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

Table Promotions 
[PromoId] int pk, 
[PromoCode] nvarchar 

Когда пользователь получает промо-код, вы бы вставить значение в используемых кодов, а также промо-код доставлен им будет конкатенация промо-код и ID в используемой таблице кодов.

Тогда вы также можете установить уникальное ограничение на UserId | PromoId в таблице используемых кодов, чтобы обеспечить только один код на промо на каждого пользователя.

Это имеет преимущество, заключающееся в сохранении записи используемых кодов и уменьшении сложности необходимости в объемной вставке, которая потенциально может привести к дублированию случайно. Он также имеет то преимущество, что не требует блокировки ...

2

Одним из очень удобных встроенных типов данных для генерации уникальных кодов, которые нелегко догадаться, является тип данных uniqueidentifier. Вы можете использовать это для генерации уникального кода, создавая его автоматически генерируемое значение (используя функцию newid()). Поскольку идентификаторы GUID находятся в HEX и не генерируются последовательно в отличие от столбцов идентификации, невозможно предсказать, какие коды будут или будут созданы, что сделает ваш процесс менее уязвимым для кого-то, просто пытающегося выполнить коды в последовательности. Количество возможных уникальных идентификаторов очень велико.

Я сделал предположение, что вам будет нужен только один промо-код на человека для каждого вашего промо. Способ, которым вы можете сделать это в своей базе данных, - это иметь таблицу, мой пример называется 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 
0

John P дал вам отличный ответ, но я нахожу GUID, громоздки для использования в качестве кода ваучера из-за длины строки.

Посмотрите на вопрос how to generate a voucher code in c#? и, конечно же, на мой ответ :) Хотя вы просите решение SQL, вы, вероятно, можете адаптировать идеи, представленные там.

Я бы также рекомендовал вам не удалять коды, которые были использованы; как вы будете уверены, что код, представленный клиентом, был создан вашей системой?