2017-02-10 9 views
1

Alle,So lösen Sie Concurrency-Problem?

Ich benutze MySql 5.7 in meiner Anwendung. Ich versuche, meine Speicherfunktion Concurrency Safe zu machen. Ich werde das mit einem Beispiel erklären.

Beispiel: Ich habe zwei Admin Benutzer Admin 1 und Admin 2. Wir haben eine Produkttabelle und wir haben einen Produkttabelleneintrag mit Produktcode "P1". Angenommen, Admin 1 und Admin 2 sind im System angemeldet und versuchen, den Produkteintrag mit dem Code "P1" gleichzeitig zu aktualisieren.

Ich muss einen der Benutzer informieren, dass die Datensätze, die Sie versuchen zu ändern, von einem anderen Benutzer aktualisiert wird, und versuchen Sie es nach einiger Zeit erneut.

Ich benutze Transaktion und änderte nicht MySql Standard-Transaktionslevel (wiederholbar lesen). Ich versuche, es zu lösen, indem ich "FÜR AKTUALISIERUNG WÄHLEN" benutze (eingeschlossen eine wo Bedingung, um mit geänderter Zeit zu überprüfen). Diese "Where" -Bedingung wird das Concurrency-Problem für jene Transaktionen lösen, die bereits festgeschrieben sind. Wenn jedoch zwei Transaktionen gleichzeitig gestartet werden und die erste Transaktion vor dem Sperrzeitlimit festgeschrieben wird, überschreibt die zweite Transaktion beim Ausführen der zweiten Transaktion die erste Transaktion.

bitte Ihre Ideen

Vielen Dank im Voraus

teilen
+0

Sie könnten einfach eine 'LOCK TABLES Produkt WRITE' machen, bevor der kritische Abschnitt auftaucht. Vergiss nicht danach zu entsperren. – apokryfos

+0

@apokryfos Sperren einer ganzen Tabelle zu einem Ende eine Bearbeitung eines einzelnen Datensatzes ist nicht wirklich eine effiziente Lösung – Shadow

+0

Ich denke, es kann eine der Lösung sein: Verwenden Sie InnoDB-Engine und 'wählen Sie ... für das Update ' – Wizard

Antwort

3

Nun gibt hier eigentlich zwei Fragen sind.

Zuerst wird einer der Admins eine Sperre für die Zeile vor der anderen erhalten, also nimmt admin2 die Sperre an, bevor Admin1 die Transaktion abschließt, dann wird die Transaktion von Admin2 stattfinden.

Das ist also alles, was das DBMS für Sie erledigt.

Aber das zweite Problem ist natürlich, wenn beide Admin1 und Admin2 versuchen, die gleiche Spalte (n) zu aktualisieren. In diesem Fall wird das Update von admin1 durch das Update von admin2 überschrieben. Die einzige Möglichkeit, dies zu verhindern, wenn Sie das stoppen möchten, besteht darin, das UPDATE sehr spezifisch zu machen, was es aktualisiert. Mit anderen Worten muss das UPDATE so etwas wie diese

UPDATE table SET col1 = 'NewValue' 
WHERE usual criteria 
    AND col1 = 'Its Original Value' 

So bedeutet dies, dass, wenn Sie die ursprünglichen Daten aus dieser Zeile an den Benutzer in einer Form präsentieren, müssen Sie irgendwie daran erinnern, was sein ursprünglicher Zustand sowie Erfassung war sein neuer Status, zu dem der Administrator es geändert hat.

Natürlich muss der PHP-Code auch geschrieben werden, um die Tatsache zu erfassen, dass das UPDATE nicht stattgefunden hat und etwas an das Admin-Update zurückgegeben wurde, das nun fehlgeschlagen ist. Zeigen Sie den neuen Wert in der fraglichen Spalte und geben Sie einen Hinweis, dass das Update fehlgeschlagen ist, weil jemand anderes dieses Feld bereits geändert hat und sie entweder die Änderung vergessen oder die Änderung über das andere Admin-Update anwenden kann.

0

Es gibt diese Technik, die Sie verwenden können, um es zu steuern, ohne die Tabelle zu sperren oder das Update zu steuern, das Sie tun sollten.

ein Feld auf dem Tisch erstellen, die eine Version für die Registrierung werden:

mit diesem
alter table someTable add column version not null integer default 0; 

Es wird keine Notwendigkeit, jeden Insert-Code zu ändern.

Jedes Mal, wenn ein Benutzer eine Registrierung zum Aktualisieren abruft, vergewissern Sie sich, dass die Version auch im Objekt (oder Formular, m oder wie auch immer Sie Ihre Entität im System verarbeiten) enthalten ist.

Dann müssen Sie eine before update trigger für Ihre Tabelle erstellen, die überprüft, ob die Version der aktuellen Registrierung immer noch die gleiche ist, so dass Sie aktualisieren, wenn Sie nicht einen Fehler auslösen. Etwas wie:

delimiter $$ 
create trigger trg_check_version BEFORE UPDATE 
     ON yourTable 
     for each row 
    begin 
     if NEW.version != OLD.version then 
      signal sqlstate '45000' set message_text = 'Field outdated'; 
     else 
      NEW.version = NEW.version + 1; 
     end if; 
    end$$ 
delimiter; 

Dann behandeln Sie den Fehler in Ihrem PHP-Code. Dieser Befehl signal funktioniert nur auf MySql 5.5 oder höher. Schauen Sie sich das an thread