Ini adalah properti dari isolasi transaksi. Ada banyak hal yang ditulis tentangnya dan saya akan sangat merekomendasikan ikhtisarnya di Mendesain Data-Intensive Aplikasi . Saya merasa itu adalah deskripsi yang paling membantu dalam meningkatkan pemahaman pribadi saya.
Level postgres default adalah READ COMMITTED yang memungkinkan setiap transaksi bersamaan ini untuk melihat yang serupa (keadaan dana yang tersedia) meskipun mereka harus bergantung.
Salah satu cara untuk mengatasinya adalah dengan menandai setiap transaksi ini sebagai konsistensi "SERIALIZABLE".
Ini harus menegakkan kebenaran aplikasi Anda dengan mengorbankan ketersediaan, yaitu dalam hal ini transaksi kedua tidak akan diizinkan untuk mengubah catatan dan akan ditolak, yang memerlukan percobaan ulang. Untuk POC atau aplikasi lalu lintas rendah ini biasanya merupakan langkah pertama yang dapat diterima karena Anda dapat memastikan kebenaran untuk saat ini.
Juga dalam buku yang dirujuk di atas saya pikir ada contoh bagaimana menangani ketersediaan ATM. Mereka memungkinkan kondisi balapan ini dan pengguna melakukan penarikan berlebih jika mereka tidak dapat terhubung ke bank terpusat tetapi mengikat penarikan maksimum untuk meminimalkan radius ledakan!
Cara arsitektur lain untuk mengatasi ini adalah dengan membuat transaksi offline dan membuatnya tidak sinkron, sehingga setiap transaksi yang dipanggil pengguna dipublikasikan ke antrian, dan kemudian dengan memiliki satu konsumen antrian, Anda secara alami menghindari kondisi balapan apa pun. Pengorbanan di sini serupa, ada throughput tetap yang tersedia dari satu pekerja, tetapi ini membantu mengatasi masalah kebenaran untuk saat ini :P
Mengunci di seluruh mesin (seperti menggunakan redis di seluruh postgres/grpc) disebut penguncian terdistribusi dan memiliki banyak tulisan tentangnya https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html