Ich betreibe eine Auktions-Website in Produktion. Ich habe ein Auktionsmodell und ein Gebotsmodell. Die Auktionszeile enthält die Endzeit, den aktuellen Preis, die Anzahl der Gebote, den Benutzernamen des letzten Bieters usw. Eine Gebotszeile enthält einen Benutzernamen, eine Auktions-ID, einen Zeitstempel, einen Preis usw.
Auf der Auktionsseite möchte ich die Statistiken der Auktion und die letzten zehn Bieter mit dem aktuellen Preis der Auktion anzeigen. Wenn ich also ein Gebot speichere, füge ich der Gebotstabelle eine Zeile hinzu, aktualisiere das Konto des Benutzers und die Auktionszeile - alles in einem Vorgang.
Dies ist mein vereinfachtes Bid-Modell:
class Bid < ActiveRecord::Base
belongs_to :auction, :inverse_of => :bids
belongs_to :account, :inverse_of => :bids
scope :recent, order('id DESC').limit(10) # used to get last ten bids
before_create :update_auction
after_create :update_account
def update_auction
auction.lock!
auction.highest_bidder = username
auction.price = ...
# more stuff
auction.save!
end
def update_account
# do stuff
account.save!
end
Wenn jedoch genügend Leute gleichzeitig auf die Gebotsschaltfläche klicken, werden die Auktionsstatistiken inkonsistent. Der Zähler weicht um ein oder zwei Punkte ab, oder der Höchstbietende stimmt nicht mit der letzten Zeile der Gebotstabelle überein. Ich dachte, da diese drei Schreibvorgänge in eine Transaktion eingeschlossen waren und ich die eine gemeinsame Zeile (Auktionen) sperre, wären die Daten in Ordnung, aber das ist nicht der Fall.
Ich könnte die Anwendung umschreiben, um die Gebotstabelle dynamisch abzufragen, um jeden Gewinner, die Anzahl der Gebote usw. zu finden, aber das verkompliziert viele andere Abfragen, die ich mache.
Was ist also die geeignete Gleichzeitigkeitskontrolle hier? Ich muss einen Gewinner in der Auktionsreihe speichern, aber dieser Gewinner muss die letzte Reihe in der Gebotstabelle sein. Und ich bekomme viele Schreibvorgänge in dieselbe Zeile auf einmal.