Ich habe einige (php) Code, der kritische Updates auf eine InnoDB-Tabelle durchführt.
Ich verwende (SELECT ... FOR UPDATE), also muss ich mich innerhalb einer Transaktion befinden.
Dieser Code wird ausgeführt, wenn Daten von einem Formular gesendet werden, und ich habe ein Nachrichtensystem vorhanden, so dass Fehler-/Erfolgsmeldungen in einer Datenbank gespeichert werden und aus der Datenbank extrahiert werden, wenn eine Seite das nächste Mal gerendert wird.
Einige Pseudocode: (Ich lasse Dinge wie die try/catch-Blöcke und Escaping weg, die ich in meinem echten Code habe)
beginTransaction();
query("SELECT * FROM `table` WHERE id=1 FOR UPDATE");
$x=$_POST[$x];
query("UPDATE `table` SET `field` = $X");
//add other data in the db related to $X
query("INSERT INTO `othertable` (x,y,x) VALUES (......)");
//check for various errors...
$erros=0
if ($error_condition_1) {
messageSystem("Error Condition 1!")
$errors+=1;
}
if ($error_condition_2) {
messageSystem("Error Condition 2!")
$errors+=1;
}
if ($errors) {
rollBackTransaction();
} else {
commitTransaction();
}
Das Problem liegt auf der Hand: Wenn messageSystem den Fehler in der Datenbank speichert, werden die Änderungen später rückgängig gemacht, und der Benutzer wird die Fehlermeldungen nie sehen.
Es gibt zwei einfache Lösungen, die ich sehe:
- Ändern Sie meinen Code so, dass
messageSystem
wird außerhalb der Transaktion aufgerufen. Es ist jedoch besser lesbar und schneller zu schreiben, wenn ich es wie oben beschrieben inline machen kann. Und was ist, wenn es sich um Bibliothekscode handelt, der sich bereits in einer verschachtelten Transaktion befindet? - Ändern Sie
messageSystem
so dass es seine eigene Verbindung zur Datenbank verwendet. Aber was ist, wenn ich messageSystem komplizierter mache und entscheide, dass es einen Eintrag in der Datenbank sperren muss?session
Tabelle, bevor es Nachrichten zu dieser Sitzung hinzufügt. Dies könnte zu einem Deadlock führen, wenn mein Hauptcode die Sitzung aus irgendeinem Grund ebenfalls gesperrt hat. - Prüfen Sie vor der Transaktion auf Fehler. Tatsächlich muss ich aber die betreffenden Zeilen durch Auswahl von "FOR UPDATE" gesperrt haben. antes de Ich kann die Eingabe validieren.
Daher meine Frage: Gibt es eine Möglichkeit, X innerhalb einer (möglicherweise verschachtelten) Transaktion zu übertragen, so dass, wenn die Transaktion zurückgesetzt wird, X trotzdem übertragen wird.
Oder gibt es eine gute Möglichkeit, das von mir beschriebene Problem zu vermeiden?
Danke!