2013-07-17 58 views
1

我有一個表,其中有兩列避免重複條目,而不是關鍵字段

key -> Primary Key, auto incremented 
reqNumber -> This is a custom generated value 

的reqNumber的結構爲年/月/日/數字,其中數字是已請求的次數那天。因此,例如,如果3個請求已於今日和2昨天,該表將具有

key reqNumber 
1  2013/07/16/001 
2  2013/07/16/002 
3  2013/07/17/001 
4  2013/07/17/002 
5  2013/07/17/003 

我遇到的問題是,有時多個用戶保存在同一時間。進行保存的過程首先檢查今天創建了多少個,然後將其添加1,因此對於上面的內容,它會看到3個是今天創建的,因此下一個將是4.之後,它執行插入操作。

但是如果兩個用戶同時點擊保存,他們都得到4,這意味着當插入發生我得到了兩次2013/07/17/004。

有沒有辦法避免這種情況,無論是在SQL或.Net?鎖是唯一的方法,那些會減慢性能是否正確?

+4

您應該在同一個事務中執行'select'和'update',並鎖定表,直到'update'完成。這樣一次只有一個用戶可以訪問表,其他用戶則等待事務完成。 –

回答

1

首先我會圍繞選擇和更新進行交易。

第二我只會更新使用樂觀斷線鎖定(意思是update table where key = TheKey and reqNumber = TheValueYouSelectedToCount),並確保您有一行更新。如果你有0行更新,這意味着其他人已經更新它。

這樣你就不能「鬆」的更新

3

如果您希望應用程序能夠擴展,你將要創建一個新表:

CREATE TABLE DayCounter (
    LastReset DateTime NOT NULL, 
    NextValue INT NOT NULL 
) 

然後,你要用一個FUNCTION這樣你就可以隨意得到一個可用值:

CREATE FUNCTION NextCounter() 
    RETURNS CHAR(3) 
AS 
BEGIN 
    BEGIN TRANSACTION 
     DECLARE @LastReset DATETIME 
     DECLARE @NextValue INT 

     SELECT @LastReset = LastReset FROM DayCounter 
     IF (DATEPART(DAY, DATEADD(DAY, 1, @LastReset)) = DATEPART(DAY, GETDATE()) 
      UPDATE DayCounter SET LastReset = GETDATE(), NextValue = 1 

     SELECT @NextValue = NextValue FROM DayCounter 
     UPDATE DayCounter SET NextValue = NextValue + 1 
    COMMIT TRANSACTION 

    RETURN RIGHT('000' + CAST(@NextValue AS CHAR), 3) 
END 

所以現在你可以建立一個字符串連接在一起的值更新語句,但它的安全距離科爾isod 它管理每天重置。

+0

使用交易是否可以避免碰撞?如果不是這樣,那麼如果2個用戶同時擊中該功能,他們是否有機會獲得相同的計數器? – Paritosh

+0

@Paritosh,通過輸入事務,它鎖定了表並保持了一個髒讀的發生。因此這消除了碰撞的可能性。 –

+0

沒有理由將業務邏輯移入數據庫。所有的邏輯應該保持在一個層次 – Skyp

1

如果reqNumber必須是唯一的,那麼數據庫對該列應該有一個UNIQUE約束。添加這個選項可以提供另一個選項:在沒有鎖的情況下嘗試一次,如果插入失敗,請使用鎖再次嘗試。憑藉高讀/寫率和低衝突頻率,這可以比每次交易的解決方案表現得更好。