2015-04-23 25 views
5

Mam tabeli, który wygląda tak:Jak obsługiwać równoczesne żądania, które usuwają i tworzą te same wiersze?

game_stats tabeli:

przesłane
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' | ... 

danych użytkownika dla danej gry luzem, przedstawiając dane obu graczy naraz. Na przykład:

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

Przesłanie tego do mojego serwera powinno spowodować powstanie pierwszej tabeli.

Zamiast aktualizacji istniejących wierszy, gdy te same dane są ponownie składane (z wersjami, na przykład), co robię w moim kontroler jest najpierw usunąć wszystkie istniejące wiersze w tabeli game_stats które mają daną 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 

Działa to dobrze na pojedynczym lub pojedynczym serwerze procesów. Problem polega na tym, że używam Unicorn, który jest serwerem wieloprocesowym. Jeśli dwa wnioski są w tym samym czasie, pojawia się stan Rasa:

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

Wynik: Wiele wierszy game_stat z tych samych danych.

Wierzę, że blokowanie wierszy lub tabeli jest sposobem na uniknięcie wielu aktualizacji w tym samym czasie - ale nie mogę wymyślić, jak to zrobić. Połączenie z transakcją wydaje się słuszne, ale tak naprawdę nie rozumiem dlaczego.

EDIT

Aby wyjaśnić, dlaczego nie mogę dowiedzieć się, jak korzystać z blokady: Nie mogę zablokować jeden wiersz na raz, ponieważ rząd jest po prostu usunięte i nie modyfikowane.

Odpowiedz

0

AR nie obsługuje domyślnie blokowania na poziomie stołu. Będziesz musiał wykonać polecenie SQL lub użyć klejnotu, np. Monogamy

Zawijanie instrukcji składowania w transakcji przyspieszy sprawę, jeśli nic więcej.

Inną alternatywą jest zastosowanie zamka z Redis. Dostępne są również klejnoty takie jak redis-lock. Prawdopodobnie będzie to mniej ryzykowne, ponieważ nie dotknie DB, a Ty możesz ustawić klucze Redis, aby wygasły.