2016-02-12 117 views
0

因此,我有多個調用C#方法的ajax請求,其中包括檢查數據庫中的值並將其減1。針對異步請求同時觸發數據庫的解決方案

public SomeModel Get(int id) 
    ... 
    credit.Available -= 1; 
    dbContext.SaveChanges(); 

因此,從理論上講,每次該方法運行時,可用信用減1。但是,因爲它們幾乎平行運行,所以credit.Available總是相同的,並且僅減少一次,例如,即使它運行5次。如果數字是20次,則會減少兩次

可以做些什麼來解決這個問題?

+0

不要爲此使用ORM。考慮你的代碼的作用 - 所有5個用戶讀取相同的值,例如10.所有5個將其減1,然後所有5個保存* same *值,9.如果你使用了SQL命令,比如'UPDATE ... SET AVAILABLE = AVAILABLE-1'你沒有問題 –

+0

重複解釋了爲什麼ORMs不能增加/減少,但這個問題提供了一個實際的解決方案 –

+0

@PanagiotisKanavos,繼續,我在聽 – chiapa

回答

0

可以鎖定關鍵部分:

private static readonly object o = new Object(); 

public SomeModel Get(int id) 

    lock (o) 
    { 
     ... 
     credit.Availbale -= 1; 
     dbContext.SaveChanges(); 
    } 

你鎖定的對象必須是靜態的,沒有任何實例。這樣,多個線程將不得不爲相同的鎖運行,因此不會交錯執行。

+1

在C#中使用鎖時,如果真的想要鎖定數據庫端,似乎並不是最好的解決方案。 – jhilden

+0

他沒有談論前端層中的工作負載均衡器或多個節點,所以我假設他只有一臺服務器。鎖定應用程序是一種非常普遍的做法。他還沒有任何性能問題(還沒?),所以早期優化沒有意義。指出你的觀點,因爲它違背了所有常見做法。此外,downvoting沒有意義,冷靜下來:) – pid

+0

這隻會損害吞吐量的具體方法。它將*不*防止來自其他方法的無效更新。數據庫應該能夠爲數千個併發用戶提供服務。併發問題應該通過修改代碼來解決,而不是限制訪問。甚至一個桌面應用程序也不應該在使用簡單的UPDATE時使用客戶端鎖 –

1

我建議使用原始SQL或SQL存儲過程來完成這項工作。事情是這樣的:

var sql = "UPDATE tbl SET Balance = Balance - 1 WHERE id = @id"; 
dbContext.ExecuteSqlCommand(sql, id); 
+0

那麼代碼會在那裏? – chiapa

+0

@chiapa我添加了一個如何使用EF調用它的示例。 – jhilden

0

你可以使用一個存儲過程來更新在爲你的同時數據庫值:

UPDATE tbl 
SET Balance = Balance - 1 
WHERE id = @id 

如果您正在使用實體框架,你可以使用以下稱此在做了。

+0

如果5個用戶試圖保存相同的錯誤值,則使用存儲過程根本無濟於事 –

+0

@PanagiotisKanavos但是,如果使用返回值運行更新腳本,它不會保存錯誤的值。 –

+0

無論是存儲過程還是原始語句都無關緊要。這是重要的內容。簡單地寫一個帶有未指定內容的存儲過程將無濟於事 –

相關問題