Dies ist eine Eigenschaft der Transaktionsisolation. Es ist viel darüber geschrieben worden und ich würde die Übersicht in Designing Data-Intensive wärmstens empfehlen Anwendungen . Ich fand es die hilfreichste Beschreibung, um mein persönliches Verständnis zu verbessern.
Die standardmäßige Postgres-Ebene ist READ COMMITTED Dadurch kann jede dieser gleichzeitigen Transaktionen einen ähnlichen Status (Geld verfügbar) sehen, obwohl sie abhängig sein sollten.
Eine Möglichkeit, dies zu beheben, wäre, jede dieser Transaktionen als "SERIALIZABLE"-Konsistenz. zu markieren
Dies sollte die Korrektheit Ihres Antrags auf Kosten der Verfügbarkeit erzwingen, dh in diesem Fall darf die zweite Transaktion die Datensätze nicht ändern und würde abgelehnt, was einen erneuten Versuch erfordern würde. Für einen POC oder eine Anwendung mit geringem Datenverkehr ist dies normalerweise ein absolut akzeptabler erster Schritt, da Sie die Korrektheit für jetzt sicherstellen können.
Auch in dem Buch, auf das oben verwiesen wird, gab es meines Erachtens ein Beispiel dafür, wie Geldautomaten mit der Verfügbarkeit umgehen. Sie ermöglichen diese Wettlaufbedingung und den Benutzer zu überziehen, wenn er nicht in der Lage ist, sich mit der zentralisierten Bank zu verbinden, aber den maximalen Rückzug begrenzt, um den Explosionsradius zu minimieren!
Eine andere architektonische Möglichkeit, dies anzugehen, besteht darin, die Transaktionen offline zu schalten und sie asynchron zu machen, sodass jede vom Benutzer aufgerufene Transaktion in einer Warteschlange veröffentlicht wird und Sie dann natürlich alle Race-Bedingungen vermeiden, indem Sie einen einzigen Verbraucher der Warteschlange haben. Der Kompromiss hier ist ähnlich, es gibt einen festen Durchsatz, der von einem einzelnen Worker verfügbar ist, aber es hilft, das Korrektheitsproblem für jetzt anzugehen :P
Maschinenübergreifendes Sperren (wie die Verwendung von redis über postgres/grpc) wird als verteiltes Sperren bezeichnet und es wurde viel darüber geschrieben https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html