Detta är en egenskap för transaktionsisolering. Det finns mycket skrivet om det och jag rekommenderar starkt översikten i Designing Data-Intensive Applikationer . Jag tyckte att det var den mest användbara beskrivningen för att förbättra min personliga förståelse.
Standardnivån för postgres är LÄS ENGAGERAD vilket gör att var och en av dessa samtidiga transaktioner kan se en liknande (tillgängliga medel) även om de borde vara beroende.
Ett sätt att lösa detta skulle vara att markera var och en av dessa transaktioner som "SERIALISERBAR" konsistens.
Detta bör upprätthålla korrektheten av din ansökan till kostnaden för tillgängligheten, dvs i det här fallet kommer den andra transaktionen inte att tillåtas att modifiera posterna och skulle avvisas, vilket skulle kräva ett nytt försök. För en POC eller en applikation med låg trafik är detta vanligtvis ett helt acceptabelt första steg eftersom du kan säkerställa korrektheten just nu.
Även i boken som refereras till ovan tror jag att det fanns ett exempel på hur bankomater hanterar tillgänglighet. De tillåter detta tävlingstillstånd och användaren att övertrassera om de inte kan ansluta till den centraliserade banken men begränsar maximalt uttag för att minimera sprängradien!
Ett annat arkitektoniskt sätt att ta itu med detta är att ta transaktionerna offline och göra dem asynkrona, så att varje anropad transaktion publiceras i en kö, och sedan genom att ha en enda konsument av kön undviker du naturligtvis alla tävlingsförhållanden. Avvägningen här är liknande det finns en fast genomströmning tillgänglig från en enskild arbetare, men det hjälper till att lösa korrekthetsproblemet just nu :P
Låsning över maskiner (som att använda redis över postgres/grpc) kallas distribuerad låsning och har skrivit en hel del om det https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html