2015-04-23 44 views
5

我有一個表,如下所示:如何處理刪除並創建相同行的併發請求?

game_stats表:

id | game_id | player_id | stats | (many other cols...) 
---------------------- 
1 | 'game_abc' | 8 | 'R R A B S' | ... 
2 | 'game_abc' | 9 | 'S B A S' | ... 

用戶上傳散裝一個給定的遊戲數據,同時提交這兩個球員的數據。例如:

"game": { 
    id: 'game_abc', 
    player_stats: { 
    8: { 
     stats: 'R R A B S' 
    }, 
    9: { 
     stats: 'S B A S' 
    } 
    } 
} 

將此提交給我的服務器應導致第一個表。

相反,當同樣的數據再次提交(與修訂,例如)我做什麼,在我的控制器首先刪除game_stats表具有給定的game_id所有現有行更新現有行:

class GameStatController 
    def update 
     GameStat.where("game_id = ?", game_id).destroy_all 
     params[:game][:player_stats].each do |stats| 
     game_stat.save 
     end 
    end 
end 

這適用於單線程或單進程服務器。問題是我正在運行Unicorn,它是一個多進程服務器。如果兩個請求在同一時間進來,我得到一個競爭條件:

Request 1: GameStat.where(...).destroy_all 
Request 2: GameStat.where(...).destroy_all 
Request 1: Save new game_stats 
Request 2: Save new game_stats 

結果:與相同數據的多個game_stat行。

我相信鎖定行或表是防止多個更新同時進行的方式 - 但我無法弄清楚如何去做。結合交易似乎是正確的事情,但我不明白爲什麼。

編輯

爲了澄清我爲什麼不能弄清楚如何使用鎖:我不能在同一時間鎖定單排,自排簡直是刪除,不是修改。

回答

0

默認情況下,AR不支持表級鎖定。你將不得不執行數據庫特定的SQL或者使用像下面這樣的寶石:Monogamy

在事務中包含保存語句將會加快速度,如果沒有其他的話。

另一種選擇是使用Redis實現鎖定。寶石像redis-lock也可用。這可能會降低風險,因爲它不會觸及數據庫,並且您可以將Redis鍵設置爲過期。