Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie werden Transaktionen und Sperren richtig verwendet, um die Datenbankintegrität sicherzustellen?

Soweit so gut, dies verhindert zumindest, dass der Benutzer in mehreren Sitzungen zur Kasse geht (mehrere Versuche, dieselbe Karte auszuchecken – gut, um mit Doppelklicks umzugehen.)

Wie prüfen Sie? Mit einem Standard SELECT oder mit einem SELECT ... FOR UPDATE ? Basierend auf Schritt 5 vermute ich, dass Sie eine reservierte Spalte für das Element oder etwas Ähnliches überprüfen.

Das Problem dabei ist, dass die SELECT ... FOR UPDATE in Schritt 2 wird FOR UPDATE NICHT angewendet alles andere sperren. Es gilt nur für das, was SELECT ist ed:das cart-item Tisch. Basierend auf dem Namen wird dies für jeden Warenkorb/Benutzer ein anderer Datensatz sein. Das bedeutet, dass andere Transaktionen NICHT blockiert werden.

Nach dem oben Gesagten, basierend auf den von Ihnen bereitgestellten Informationen, kann es passieren, dass mehrere Personen denselben Artikel kaufen, wenn Sie SELECT ... FOR UPDATE nicht verwenden bei Schritt 3.

Vorgeschlagene Lösung

  1. Transaktion beginnen
  2. SELECT ... FOR UPDATE das cart-item Tabelle.

Dadurch wird die Ausführung eines Doppelklicks gesperrt. Was Sie hier auswählen, sollte eine Art "Warenkorb bestellt"-Spalte sein. Wenn Sie dies tun, wird eine zweite Transaktion hier anhalten und warten, bis die erste abgeschlossen ist, und dann das Ergebnis lesen, das die erste in der Datenbank gespeichert hat.

Stellen Sie sicher, dass Sie hier den Bestellvorgang beenden, wenn der cart-item Tabelle sagt, dass es bereits bestellt wurde.

  1. SELECT ... FOR UPDATE die Tabelle, in der Sie notieren, ob ein Artikel reserviert wurde.

Dadurch werden ANDERE Warenkörbe/Benutzer daran gehindert, diese Artikel zu lesen.

Wenn die Exemplare nicht reserviert sind, fahren Sie basierend auf dem Ergebnis fort mit:

  1. UPDATE ... die Tabelle in Schritt 3 und markieren Sie den Artikel als reserviert. Führen Sie ein beliebiges anderes INSERT aus s und UPDATE s brauchen Sie auch.

  2. Zahlung leisten. Führen Sie ein Rollback durch, wenn der Zahlungsdienst sagt, dass die Zahlung nicht funktioniert hat.

  3. Bei Erfolg Zahlung verbuchen.

  4. Transaktion festschreiben

Stellen Sie sicher, dass Sie nichts tun, was zwischen den Schritten 5 und 7 fehlschlagen könnte (z. B. E-Mails senden), da Sie sonst möglicherweise eine Zahlung vornehmen, ohne dass diese aufgezeichnet wird, falls die Transaktion rückgängig gemacht wird.

Schritt 3 ist der wichtige Schritt, um sicherzustellen, dass nicht zwei (oder mehr) Personen versuchen, denselben Artikel zu bestellen. Wenn es zwei Personen versuchen, bleibt die Webseite der zweiten Person hängen, während sie die erste verarbeitet. Wenn der erste fertig ist, liest der zweite die Spalte "reserviert" und Sie können dem Benutzer eine Nachricht zurücksenden, dass jemand diesen Artikel bereits gekauft hat.

Zahlung in Transaktion oder nicht

Dies ist subjektiv. Im Allgemeinen möchten Sie Transaktionen so schnell wie möglich schließen, um zu vermeiden, dass mehrere Personen gleichzeitig von der Interaktion mit der Datenbank ausgeschlossen werden.

In diesem Fall möchten Sie jedoch, dass sie warten. Es kommt nur darauf an, wie lange.

Wenn Sie die Transaktion vor der Zahlung festschreiben möchten, müssen Sie Ihren Fortschritt in einer Zwischentabelle aufzeichnen, die Zahlung ausführen und dann das Ergebnis aufzeichnen. Beachten Sie, dass Sie die aktualisierten Artikelreservierungsdatensätze manuell rückgängig machen müssen, wenn die Zahlung fehlschlägt.

SELECT ... FOR UPDATE für nicht vorhandene Zeilen

Nur ein Wort der Warnung, falls Ihr Tabellendesign das Einfügen von Zeilen beinhaltet, wo Sie früher SELECT ... FOR UPDATE müssen :Wenn eine Zeile nicht existiert, bewirkt diese Transaktion NICHT, dass andere Transaktionen warten, wenn sie auch SELECT ... FOR UPDATE dieselbe nicht vorhandene Zeile.

Stellen Sie also sicher, dass Sie Ihre Anfragen immer serialisieren, indem Sie SELECT ... FOR UPDATE ausführen in einer Zeile, von der Sie wissen, dass sie zuerst existiert. Dann können Sie SELECT ... FOR UPDATE in der Zeile, die möglicherweise noch vorhanden ist oder noch nicht vorhanden ist. (Versuchen Sie nicht, nur ein SELECT auszuführen in der Zeile, die vorhanden sein kann oder nicht, da Sie den Status der Zeile zum Zeitpunkt des Transaktionsstarts lesen und nicht in dem Moment, in dem Sie SELECT ausführen . Also, SELECT ... FOR UPDATE in nicht existierenden Zeilen ist immer noch etwas, das Sie tun müssen, um die aktuellsten Informationen zu erhalten, aber seien Sie sich bewusst, dass andere Transaktionen dadurch nicht warten müssen.)