Eine Möglichkeit, Deadlocks zu bewältigen, besteht darin, einen Wiederholungsmechanismus zu haben, der auf ein zufälliges Intervall wartet und versucht, die Transaktion erneut auszuführen. Das zufällige Intervall ist notwendig, damit die kollidierenden Transaktionen nicht ständig aufeinanderprallen und eine sogenannte Live-Sperre verursachen - etwas, das noch unangenehmer zu debuggen ist. Tatsächlich benötigen die meisten komplexen Anwendungen früher oder später einen solchen Wiederholungsmechanismus, wenn sie mit Transaktionsserialisierungsfehlern umgehen müssen.
Wenn Sie die Ursache des Deadlocks ermitteln können, ist es natürlich viel besser, ihn zu beseitigen, oder wird komme zurück, um dich zu beißen. In fast allen Fällen, selbst wenn der Deadlock-Zustand selten auftritt, lohnt sich der kleine Durchsatz- und Codierungsaufwand, um die Sperren in deterministischer Reihenfolge oder grobkörnigere Sperren zu erhalten, um den gelegentlichen großen Latenzeinbruch und die plötzliche Leistungsklippe zu vermeiden beim Skalieren der Parallelität.
Wenn Sie ständig zwei INSERT-Anweisungen Deadlocks erhalten, handelt es sich höchstwahrscheinlich um ein Problem mit der eindeutigen Index-Einfügereihenfolge. Versuchen Sie beispielsweise Folgendes in zwei psql-Befehlsfenstern:
Thread A | Thread B
BEGIN; | BEGIN;
| INSERT uniq=1;
INSERT uniq=2; |
| INSERT uniq=2;
| block waiting for thread A to commit or rollback, to
| see if this is an unique key error.
INSERT uniq=1; |
blocks waiting |
for thread B, |
DEADLOCK |
V
Normalerweise besteht die beste Vorgehensweise zur Lösung dieses Problems darin, die übergeordneten Objekte herauszufinden, die alle diese Transaktionen schützen. Die meisten Anwendungen haben eine oder zwei primäre Entitäten wie Benutzer oder Konten, die dafür gute Kandidaten sind. Dann brauchen Sie nur noch für jede Transaktion die Sperren für die primäre Entität zu erhalten, die sie berührt, über SELECT ... FOR UPDATE. Oder wenn Sie mehrere berühren, erhalten Sie Sperren für alle, aber jedes Mal in der gleichen Reihenfolge (Reihenfolge nach Primärschlüssel ist eine gute Wahl).