2009-04-22 85 views
0

我有一個許可證密鑰/序列號的sql服務器表。 表結構是類似的東西;從序列號池中爲客戶端分配序列號

[ 
RecordId int, 
LicenceKey string, 
Status int (available, locked, used, expired etc.) 
AssignedTo int (customerId) 
.... 
] 

通過我的ASP.NET應用程序,當用戶決定購買一個許可證接受按鈕,我需要保留該用戶的許可密鑰。 我的做法是一樣,從KeysTable 選擇頂部1 licenceKey其中狀態=可用 更新KeysTable設置狀態=鎖定 然後返回鍵返回給應用程序。

我擔心的是,如果兩個asp.net線程訪問相同的記錄並返回相同licencekey。 您認爲做這樣的作業的最佳做法是什麼?有這樣一個衆所周知的問題或模式嗎? 如果我需要使用lock()語句,哪裏可以使用?

我使用SQL Server 2005,用於數據訪問的存儲過程,一個數據層一BusinessLayer和Asp.Net GUI。

感謝

回答

4

有可能無需使用明確的鎖或交易在這種情況下。

在您的存儲過程中,您可以使用UPDATE語句中的OUTPUT子句更新表並通過單個原子操作檢索許可證密鑰。

事情是這樣的:

UPDATE TOP (1) KeysTable 
SET Status = 'locked' 
OUTPUT INSERTED.LicenseKey 
-- if you want more than one column... 
-- OUTPUT INSERTED.RecordID, INSERTED.LicenseKey 
-- if you want all columns... 
-- OUTPUT INSERTED.* 
WHERE Status = 'available' 
0

我認爲你應該實際上標記鍵在你所查詢它同存儲過程不可用,否則總會有某種競爭條件。手動鎖定表格不是一種好的做法。

如果您有兩個階段的流程(例如預訂機票),您可以引入一個在特定時間段(例如30分鐘)預留鑰匙的概念,以便在查詢新鑰匙時,你同時預定它。

編輯:鎖定在業務邏輯可能會工作,如果你可以保證只有一個進程會改變數據庫,但它是在數據庫級別,最好在單個存儲過程中更好。要正確地做到這一點,您必須設置事務級別並在數據庫中使用事務,就像@Adam Robinson在他的回答中所建議的那樣。

+0

這完全不解決問題,他...他正在同一批次中執行選擇和更新,但由於他沒有任何類型的鎖定(就像使用可序列化的事務),沒有什麼能保證並行批次不會選擇相同的行。 – 2009-04-22 13:03:21

+0

其實我打算在業務層中寫一個像GetNextAvailableKey這樣的靜態方法,該方法在數據訪問方法(如選擇鍵,更新密鑰等)周圍具有lock()塊。或者,我應該編寫一個帶有SERIALIZABLE隔離級別的GetNextKey存儲過程它會選擇,更新並返回該鍵,並在調用方法中添加一個lock()塊? – UmutKa 2009-04-22 13:11:40

+0

對不起,我的答案有點不準確。請參閱編輯。 – Grzenio 2009-04-22 13:18:23

1

達到你在說什麼,你需要使用一個串行事務。要做到這一點,遵循此模式:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
GO 
BEGIN TRANSACTION 

--Execute select 
--Execute update 

COMMIT TRANSACTION 

但是,爲什麼你有一個表每一種可能的許可證密鑰?爲什麼不具有密鑰生成算法,然後在用戶購買密鑰時創建一個新密鑰?

0

您也可以嘗試除了交易中使用鎖(在SQL),以驗證只有一個線程在同一時間訪問。

我相信應用程序鎖定可能對此有所幫助。