5 Stimmen

Wie kann ich eine Gruppe von Objekten für eine Operation sperren?

In meiner Rails-Anwendung habe ich etwas Code wie diesen:

def foo
  if object_bar_exists
    raise "Kann Bar nicht zweimal erstellen!"
  end

  Bar.create
end

Der von zwei verschiedenen Anfragen an den Anwendungsserver aufgerufen werden könnte. Wenn dieser Code von zwei Anfragen gleichzeitig ausgeführt wird und sie beide die if Bedingung zur gleichen Zeit überprüfen, werden weder die bar des anderen finden und es werden 2 bars erstellt.

Was ist der beste Weg, um einen "Mutex" für "die Sammlung von Bars" zu erstellen? Eine spezielle Mutex-Tabelle in der Datenbank?

Aktualisierung

Ich möchte betonen, dass ich hier keinen Speichermutex verwenden kann, da die Parallelität über Anfragen/Prozesse und nicht Threads erfolgt.

6voto

Pan Thomakos Punkte 33342

Das Beste, was Sie tun können, ist, Ihre Operationen in einer DB-Transaktion durchzuführen. Da Sie wahrscheinlich irgendwann mehrere Anwendungen gleichzeitig ausführen und diese sehr wahrscheinlich keinen Speicher teilen werden, werden Sie auf Anwendungsebene keine Mutex-Sperre erstellen können, insbesondere wenn diese beiden Anwendungsdienste auf völlig unterschiedlichen physischen Maschinen ausgeführt werden. So führen Sie die DB-Transaktion aus:

ActiveRecord::Base.transaction do
  # Transaktionscode kommt hierhin.
end

Wenn Sie sicherstellen möchten, dass eine Rückgängigmachung der DB-Transaktion erfolgt, müssen Sie die Validierung für die Bar-Klasse aktiviert haben, damit eine ungültige Speicheranforderung eine Rückgängigmachung verursacht:

ActiveRecord::Base.transaction do
  bar = Bar.new(params[:bar])
  bar.save!
end

Wenn Sie bereits ein Bar-Objekt in der DB haben, können Sie dieses Objekt pessimistisch sperren, indem Sie Folgendes tun:

ActiveRecord::Base.transaction do
  bar = Bar.find(1, :lock => true)
  # Operationen am Bar durchführen
end

1voto

Alex Moore Punkte 3343

Wenn alle Anfragen auf der gleichen Maschine und der gleichen Ruby-Virtual-Maschine eingehen, können Sie die Mutex-Klasse von Ruby verwenden: Mutex-Dokumente.

Wenn es mehrere Maschinen oder RVMS gibt, müssen Sie eine Datenbanktransaktion verwenden, um das Bar-Objekt zu erstellen / abzurufen, vorausgesetzt, es wird irgendwie in der Datenbank gespeichert.

0voto

BeepDog Punkte 4886

Ich würde wahrscheinlich ein Singleton-Objekt im lib-Verzeichnis erstellen, sodass Sie nur eine Instanz der Sache haben und Mutexe verwenden, um darauf zu sperren.

So können Sie sicherstellen, dass zu jedem Zeitpunkt nur ein Zugriff auf die Sache möglich ist. Natürlich werden alle anderen Anfragen darauf blockieren, also ist das etwas, woran man denken sollte.

Für mehrere Maschinen müssten Sie einen Token in einer Datenbank speichern und irgendwie den Zugriff auf den Token synchronisieren. Zum Beispiel muss der Token abgefragt und herausgenommen werden, und man muss eine Art Nummer oder etwas ähnliches verfolgen, um sicherzustellen, dass Leute den Token nicht gleichzeitig entfernen können. Oder verwenden Sie einen zentralisierten Sperr-Webdienst, damit Ihre Token-Verwaltung nur an einem Ort erfolgt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X