2010-11-19 99 views
1

我開始一個項目,我需要確保大量用戶可以獲取多次促銷的促銷代碼。SQL Server獲取唯一記錄

這些代碼具有附加的貨幣價值,所以至關重要的是隻有一個代碼發送給每個用戶,並且沒有兩個用戶可以收到代碼。

我到目前爲止的計劃是在SQL Server中創建一個名爲code_pool的表格,並且每次都進行大量的代碼插入操作。

SQL Server 2005的表是這樣的......

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

然後,用戶將使用retreive存儲的過程,將得到的第一條記錄從表中晉升,然後刪除每個代碼(或更新)作爲過程的結果返回代碼之前的記錄。

我的問題是如何確保記錄被正確鎖定,以便只有一個用戶可以獲取每條記錄,並且沒有兩個用戶同時訪問proc會收到相同的代碼?

我是否需要鎖定表格/記錄,如果是這樣的話,如何在繁忙的生產環境中堆疊?

回答

1

你不想添加例如in_use(int)?當你產生新的促銷碼,IN_USE = 0,當你的存儲過程獲得的未使用的促銷代碼,它選擇第一個代碼,其中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 |在使用的代碼表上進行促銷,以確保每個用戶每個促銷只有一個代碼。

這具有保留所使用代碼的記錄的優點,並降低了需要批量插入的複雜性,這可能會偶然引入dups。它還具有不需要鎖定的優點...

2

一種非常方便的內置數據類型,用於生成不易被猜出的唯一代碼是uniqueidentifier數據類型。您可以使用它通過使其具有自動生成的值(使用newid()函數)來生成唯一代碼。由於GUID採用十六進制,而不是按順序生成,與身份列不同,因此無法預測哪些代碼已經生成或將要生成哪些代碼,從而使您的進程更不易受某人按順序嘗試代碼的影響。可能的uniqueidentifiers數量非常大。

我已經做出了這樣的假設,您只需要爲每個促銷的每個人推送一個促銷代碼。您可以在數據庫中執行此操作的方式是使用表格,我的示例將其稱爲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給你一個很好的答案,但我發現GU​​ID是笨拙用作優惠券代碼,由於字符串長度。

看看how to generate a voucher code in c#?這個問題,當然我的回答:)雖然你在問一個SQL解決方案,你可能會適應那裏給出的想法。

我也建議你不要刪除已經使用的代碼;您如何確保客戶提供的代碼是由您的系統創建的?