SQL Server получает уникальные записи - PullRequest
1 голос
/ 19 ноября 2010

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

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

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

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

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

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

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

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

Ответы [ 4 ]

2 голосов
/ 19 ноября 2010

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

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

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

0 голосов
/ 24 мая 2011

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

Посмотрите на вопрос , как генерировать код ваучера в c #? и, конечно, мой ответ :) Хотя вы запрашиваете решение SQL, вы, вероятно, можете адаптировать приведенные там идеи. *

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

0 голосов
/ 19 ноября 2010

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

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

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

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

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

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

...