Durch das Sperren von Tabellen wird verhindert, dass andere DB-Benutzer die von Ihnen gesperrten Zeilen / Tabellen beeinflussen. Sperren an und für sich stellen jedoch NICHT sicher, dass Ihre Logik in einem konsistenten Zustand ausgegeben wird.
Denken Sie an ein Bankensystem. Wenn Sie eine Rechnung online bezahlen, sind mindestens zwei Konten von der Transaktion betroffen: Ihr Konto, von dem das Geld abgezogen wird. Und das Konto des Empfängers, auf das das Geld überwiesen wird. Und das Konto der Bank, auf das sie gerne alle für die Transaktion berechneten Servicegebühren einzahlen. Angesichts der Tatsache, dass Banken (wie heutzutage jeder weiß) außerordentlich dumm sind, nehmen wir an, dass ihr System folgendermaßen funktioniert:
$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;
$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance
Jetzt, ohne Sperren und ohne Transaktionen, ist dieses System anfällig für verschiedene Rennbedingungen, von denen die größte darin besteht, dass mehrere Zahlungen auf Ihrem Konto oder auf dem Konto des Empfängers parallel ausgeführt werden. Während Ihr Code Ihr Guthaben abgerufen hat und die riesigen_overdraft_fees () und so weiter ausführt, ist es durchaus möglich, dass bei einer anderen Zahlung dieselbe Art von Code parallel ausgeführt wird. Sie werden Ihr Guthaben abrufen (z. B. 100 US-Dollar), ihre Transaktionen durchführen (die 20 US-Dollar, die Sie bezahlen, und die 30 US-Dollar, mit denen sie Sie verarschen, herausnehmen), und jetzt haben beide Codepfade zwei unterschiedliche Guthaben: 80 US-Dollar und $ 70. Abhängig davon, welches zuletzt endet, erhalten Sie eines dieser beiden Guthaben auf Ihrem Konto, anstatt der 50 US-Dollar, die Sie hätten erhalten sollen (100 bis 20 bis 30 US-Dollar). In diesem Fall "Bankfehler zu Ihren Gunsten"
Angenommen, Sie verwenden Sperren. Ihre Rechnungszahlung (20 US-Dollar) geht zuerst auf die Pipe, sodass Sie Ihren Kontodatensatz gewinnen und sperren. Jetzt haben Sie die ausschließliche Verwendung und können die 20 USD vom Guthaben abziehen und das neue Guthaben in Ruhe zurückschreiben ... und Ihr Konto erhält erwartungsgemäß 80 USD. Aber ... äh ... Sie versuchen, das Konto des Empfängers zu aktualisieren, und es ist gesperrt und länger gesperrt, als es der Code zulässt, wodurch Ihre Transaktion zeitlich begrenzt wird ... Wir haben es mit dummen Banken zu tun, anstatt einen richtigen Fehler zu haben Handling, der Code zieht nur ein exit()
, und Ihre 20 Dollar verschwinden in einem Elektronenstoß. Jetzt haben Sie 20 US-Dollar verloren, und Sie schulden dem Empfänger immer noch 20 US-Dollar, und Ihr Telefon wird wieder in Besitz genommen.
Also ... Transaktionen eingeben. Sie starten eine Transaktion, Sie belasten Ihr Konto mit 20 USD, Sie versuchen, dem Empfänger 20 USD gutzuschreiben ... und etwas explodiert erneut. Aber diesmal kann exit()
der Code nicht mehr rollback
, und Ihre 20 US-Dollar werden Ihrem Konto auf magische Weise wieder gutgeschrieben.
Am Ende läuft es darauf hinaus:
Sperren verhindern, dass andere Benutzer Datenbankeinträge stören, mit denen Sie sich befassen. Transaktionen verhindern, dass "spätere" Fehler "frühere" Dinge stören, die Sie getan haben. Keiner von beiden allein kann garantieren, dass die Dinge am Ende gut laufen. Aber zusammen tun sie es.
in der morgigen Lektion: Die Freude an Deadlocks.