2012-01-11 138 views
1

我在用戶表上有一個字段,用於保存用戶的帳戶餘額。用戶可以使用我的服務執行大量操作,這將導致其餘額的快速更改。使用mysql更新帳戶餘額

我想使用mysql的可序列化的隔離級別,以確保多個用戶操作不會錯誤地更新值。 (行動A和行動B同時要從餘額中扣除1美元。)但是,我收到了很多死鎖錯誤。

如何正確執行此操作而不會導致所有這些死鎖,並仍然保持餘額欄位處於最新狀態?

簡單模式:用戶有一個id和一個餘額。

即時通訊使用的學說,所以我做類似如下:

$con->beginTransaction(); 
$tx = $con->transaction; 
$tx->setIsolation('SERIALIZABLE'); 

$user = UserTable::getInstance()->find($userId); 
$user->setBalance($user->getBalance() + $change); 
$user->save(); 
$con->commit(); 
+2

如果您提供了架構以及選擇,更新和訪問模式,這些問題將更容易解決問題。 – atxdba 2012-01-11 23:37:58

+0

更新了問題。 – 2012-01-11 23:52:52

回答

0

首先嚐試在你的事務中使用序列化隔離級別是一個好主意。這意味着你至少知道什麼是轉換,並且隔離級別是最大的問題之一。

請注意,可序列化不是真正的可串行性。更多關於this previous answer的內容,當你有一段時間閱讀時:-)。

但是最重要的部分是,您應該考慮由於失敗的可串行性而對您的事務進行自動回滾是一個正常事實,並且正確的事情是構建您的應用程序,以便事務可能失敗並應該重播。

一個簡單的解決方案,對於會計事情我喜歡這個簡單的解決方案,因爲我們可以預測所有的事實,沒有驚喜,所以,一種解決方案是執行表鎖。這不是一個好的和優雅的解決方案,沒有行級鎖定,只是簡單的大表鎖(並且總是以相同的順序)。之後,您可以作爲單個玩家進行操作,然後釋放鎖。在表的行上沒有多用戶併發性,沒有下一行魔法鎖失敗(請參閱上一個鏈接)。這肯定會減慢你的寫操作,但是如果每個人都按照相同的順序執行表鎖,那麼你只會鎖定超時問題,沒有死鎖,並且沒有'非序列化的自動回滾'。

編輯

從您的代碼示例我不知道你能後設置的事務隔離級別的開始。您應該激活MySQL上的查詢日誌並看看哪些操作完成,然後檢查CMS運行的其他事務是否仍然處於可序列化級別。