it-swarm.com.de

Wie kann man Rennbedingungen in einer Webanwendung verhindern?

Stellen Sie sich eine E-Commerce-Site vor, auf der Alice und Bob beide die Produktlisten bearbeiten. Alice verbessert die Beschreibungen, während Bob die Preise aktualisiert. Gleichzeitig beginnen sie mit der Bearbeitung des Acme Wonder Widget. Bob beendet zuerst und speichert das Produkt mit dem neuen Preis. Alice braucht etwas länger, um die Beschreibung zu aktualisieren, und wenn sie fertig ist, speichert sie das Produkt mit ihrer neuen Beschreibung. Leider überschreibt sie auch den Preis mit dem alten Preis, der nicht beabsichtigt war.

Nach meiner Erfahrung sind diese Probleme in Web-Apps äußerst häufig. Einige Software (z. B. Wiki-Software) ist dagegen geschützt. Normalerweise schlägt der zweite Speichervorgang mit "Die Seite wurde während der Bearbeitung aktualisiert" fehl. Die meisten Websites bieten diesen Schutz jedoch nicht.

Es ist erwähnenswert, dass die Controller-Methoden an sich threadsicher sind. Normalerweise verwenden sie Datenbanktransaktionen, die sie in dem Sinne sicher machen, dass wenn Alice und Bob genau im selben Moment versuchen zu speichern, dies keine Korruption verursacht. Die Rennbedingung ergibt sich daraus, dass Alice oder Bob veraltete Daten in ihrem Browser haben.

Wie können wir solche Rennbedingungen verhindern? Insbesondere würde ich gerne wissen:

  • Welche Techniken können verwendet werden? z.B. Verfolgung des Zeitpunkts der letzten Änderung. Was sind die Vor- und Nachteile von jedem.
  • Was ist eine hilfreiche Benutzererfahrung?
  • In welchen Frameworks ist dieser Schutz eingebaut?
33
paj28

Sie müssen "Ihre Schreibvorgänge lesen", dh bevor Sie eine Änderung aufschreiben, müssen Sie den Datensatz erneut lesen und prüfen, ob seit dem letzten Lesen Änderungen daran vorgenommen wurden. Sie können dies feldweise (feinkörnig) oder basierend auf einem Zeitstempel (grobkörnig) durchführen. Während Sie diese Prüfung durchführen, benötigen Sie eine exklusive Sperre für den Datensatz. Wenn keine Änderungen vorgenommen wurden, können Sie Ihre Änderungen aufschreiben und die Sperre aufheben. Wenn sich der Datensatz in der Zwischenzeit geändert hat, brechen Sie die Transaktion ab, lösen die Sperre und benachrichtigen den Benutzer.

19
Phil

Ich habe 2 Hauptwege gesehen:

  1. Fügen Sie den Zeitstempel der letzten Aktualisierung der Seite, die verwendet wird, in eine versteckte Eingabe ein. Beim Festschreiben wird der Zeitstempel mit dem aktuellen verglichen. Wenn er nicht übereinstimmt, wurde er von einer anderen Person aktualisiert und gibt einen Fehler zurück.

    • pro: Mehrere Benutzer können verschiedene Teile der Seite bearbeiten. Die Fehlerseite kann zu einer Diff-Seite führen, auf der der zweite Benutzer seine Änderungen auf der neuen Seite zusammenführen kann.

    • con: Manchmal werden große Teile des Aufwands bei großen gleichzeitigen Bearbeitungen verschwendet.

  2. Wenn ein Benutzer beginnt, die Seitensperre für einen angemessenen Zeitraum zu bearbeiten, erhält ein anderer Benutzer beim Versuch, sie zu bearbeiten, eine Fehlerseite und muss warten, bis entweder die Sperre abläuft oder der erste Benutzer eine Festschreibung vorgenommen hat.

    • pro: Bearbeitungsaufwand wird nicht verschwendet.

    • con: Ein skrupelloser Benutzer kann eine Seite auf unbestimmte Zeit sperren. Eine Seite mit einer abgelaufenen Sperre kann möglicherweise weiterhin festgeschrieben werden, sofern nicht anders behandelt (unter Verwendung von Technik 1).

10
ratchet freak

Verwenden Sie Optimistic Concurrency Control .

Fügen Sie der betreffenden Tabelle eine versionNumber- oder versionTimestamp-Spalte hinzu (Ganzzahl ist am sichersten).

Benutzer 1 liest Datensatz:

{id:1, status:unimportant, version:5}

Benutzer 2 liest Datensatz:

{id:1, status:unimportant, version:5}

Benutzer 1 speichert den Datensatz, dies erhöht die Version:

save {id:1, status:important, version:5}
new value {id:1, status:important, version:6}

Benutzer 2 versucht, den gelesenen Datensatz zu speichern:

save {id:1, status:unimportant, version:5}
ERROR

Hibernate/JPA kann dies automatisch mit dem @Version Anmerkung

Sie müssen den Status des gelesenen Datensatzes irgendwo beibehalten, im Allgemeinen in einer Sitzung (dies ist sicherer als in einer versteckten Formularvariablen).

8
Neil McGuigan

Einige ORM-Systeme (Object Relational Mapping) erkennen, welche Felder eines Objekts sich seit dem Laden aus der Datenbank geändert haben, und erstellen die SQL-Aktualisierungsanweisung, um nur diese Werte festzulegen. ActiveRecord für Ruby on Rails ist ein solches ORM.

Der Nettoeffekt besteht darin, dass Felder, die der Benutzer nicht geändert hat, nicht in dem an die Datenbank gesendeten UPDATE-Befehl enthalten sind. Personen, die gleichzeitig verschiedene Felder aktualisieren, überschreiben die Änderungen nicht gegenseitig.

Überprüfen Sie je nach verwendeter Programmiersprache, welche ORMs verfügbar sind, und prüfen Sie, ob in einer dieser Anwendungen nur Spalten in der Datenbank aktualisiert werden, die in Ihrer Anwendung als "schmutzig" gekennzeichnet sind.

1
Greg Burghardt