Race condition di aplikasi CRUD: penyebab dan solusi praktis
Race condition di aplikasi CRUD bisa menyebabkan pesanan ganda dan total yang salah. Pelajari titik tabrakan umum serta perbaikan praktis dengan konstraint, kunci, dan penjagaan UX.

Seperti apa race condition di aplikasi CRUD
Race condition terjadi ketika dua (atau lebih) permintaan memperbarui data yang sama hampir bersamaan, dan hasil akhir bergantung pada urutan waktu. Setiap permintaan terlihat benar sendiri. Bersama-sama, mereka menghasilkan hasil yang salah.
Contoh sederhana: dua orang menekan Simpan pada rekaman pelanggan yang sama dalam waktu satu detik. Satu memperbarui email, yang lain memperbarui nomor telepon. Jika kedua permintaan mengirim seluruh rekaman, tulis kedua bisa saling menimpa; perubahan salah satu hilang tanpa error.
Fenomena ini lebih sering terlihat pada aplikasi cepat karena pengguna dapat memicu lebih banyak aksi per menit. Ini juga melonjak pada momen sibuk: flash sale, akhir bulan laporan, kampanye email besar, atau kapan pun backlog permintaan mengenai baris yang sama.
Pengguna jarang melaporkan "race condition." Mereka melaporkan gejalanya: pesanan atau komentar ganda, pembaruan yang hilang ("saya sudah menyimpan, tapi kembali seperti semula"), total yang aneh (inventori jadi negatif, penghitung mundur), atau status yang berubah tak terduga (disetujui, lalu kembali menunggu).
Retry memperparahnya. Orang klik dua kali, refresh setelah respons lambat, submit dari dua tab, atau menghadapi jaringan fluktuatif yang menyebabkan browser dan aplikasi mobile mengirim ulang. Jika server memperlakukan setiap permintaan sebagai tulis baru, Anda bisa mendapatkan dua create, dua pembayaran, atau dua perubahan status yang seharusnya terjadi sekali.
Kenapa race condition terjadi lebih sering daripada yang Anda kira
Kebanyakan aplikasi CRUD terasa sederhana: baca baris, ubah field, simpan. Masalahnya, aplikasi Anda tidak mengendalikan waktu. Database, jaringan, retry, pekerjaan latar, dan perilaku pengguna semuanya tumpang tindih.
Salah satu pemicu umum adalah dua orang mengedit rekaman yang sama. Keduanya memuat nilai "saat ini", keduanya membuat perubahan yang valid, dan simpanan terakhir diam-diam menimpa yang pertama. Tidak ada yang salah secara eksplisit, tapi satu pembaruan hilang.
Ini juga terjadi pada satu orang. Klik ganda pada tombol Simpan, mengetuk kembali dan maju, atau koneksi lambat yang mendorong seseorang menekan Submit lagi bisa mengirim tulis yang sama dua kali. Jika endpoint tidak idempoten, Anda bisa membuat duplikat, menagih dua kali, atau memajukan status dua langkah.
Kebiasaan modern menambah tumpang tindih. Banyak tab atau perangkat yang masuk ke akun yang sama dapat memicu pembaruan saling bertentangan. Pekerjaan latar (email, penagihan, sinkron, pembersihan) bisa menyentuh baris yang sama dengan permintaan web. Retry otomatis di klien, load balancer, atau job runner bisa mengulangi permintaan yang sebenarnya sudah berhasil.
Jika Anda cepat merilis fitur, rekaman yang sama sering diperbarui dari lebih banyak tempat daripada yang diingat siapa pun. Jika Anda menggunakan builder chat seperti Koder.ai, aplikasi bisa tumbuh lebih cepat lagi, jadi anggap konkurensi sebagai perilaku normal, bukan kasus tepi.
Titik tabrakan umum yang perlu diwaspadai
Race condition jarang muncul di demo "buat record". Mereka muncul di tempat dua permintaan menyentuh potongan kebenaran yang sama pada waktu hampir bersamaan. Mengetahui hotspot biasa membantu Anda merancang penulisan yang aman sejak awal.
Counter dan field "nomor berikutnya"
Apa pun yang terasa seperti "tinggal tambah 1" bisa rusak saat beban tinggi: like, view count, total, nomor faktur, nomor tiket. Pola berisiko adalah membaca nilai, menambah, lalu menulis kembali. Dua permintaan bisa membaca nilai awal yang sama dan menimpa satu sama lain.
Transisi status
Alur seperti Draft -> Submitted -> Approved -> Paid terlihat sederhana, tapi tabrakan umum terjadi. Masalah muncul ketika dua aksi memungkinkan pada saat yang sama (approve dan edit, cancel dan pay). Tanpa penjagaan, Anda bisa mendapatkan rekaman yang melewatkan langkah, berbalik, atau menampilkan status berbeda di tabel yang berbeda.
Anggap perubahan status seperti kontrak: izinkan hanya langkah valid berikutnya dan tolak yang lain.
Inventori, kapasitas, dan slot booking
Sisa kursi, jumlah stok, slot janji, dan field "kapasitas tersisa" menciptakan masalah oversell klasik. Dua pembeli checkout bersamaan, keduanya melihat ketersediaan, dan keduanya berhasil. Jika database bukan hakim akhir, lama-lama Anda akan menjual lebih dari stok.
Keunikan dan aturan "hanya satu aktif"
Beberapa aturan bersifat absolut: satu email per akun, satu langganan aktif per pengguna, satu keranjang terbuka per pengguna. Ini sering gagal ketika Anda cek dulu ("apakah sudah ada?") lalu insert. Di bawah konkurensi, kedua permintaan bisa lolos pengecekan.
Jika Anda cepat menulis alur CRUD (misalnya, dengan chat ke app di Koder.ai), catat hotspot ini sejak awal dan dukung mereka dengan konstraint dan penulisan aman, bukan hanya pengecekan UI.
Pengiriman ganda dan permintaan berulang dari UI
Banyak race condition dimulai dari sesuatu yang membosankan: aksi yang sama dikirim dua kali. Pengguna klik dua kali. Jaringan lambat sehingga mereka klik lagi. Ponsel merekam dua ketukan. Kadang tidak disengaja: halaman melakukan refresh setelah POST dan browser menawarkan untuk submit ulang.
Saat itu terjadi, backend bisa menjalankan dua create atau update secara paralel. Jika keduanya sukses, Anda mendapatkan duplikat, total yang salah, atau perubahan status yang berjalan dua kali (misalnya, approve kemudian approve lagi). Terlihat acak karena bergantung pada waktu.
Pendekatan paling aman adalah pertahanan berlapis. Perbaiki UI, tapi anggap UI akan gagal.
Perubahan praktis yang bisa diterapkan pada sebagian besar alur tulis:
- Nonaktifkan tombol submit setelah klik pertama dan tampilkan status "menyimpan" yang jelas.
- Redirect setelah POST sukses sehingga refresh tidak mengirim ulang form yang sama.
- Gunakan kunci idempoten: token unik per aksi pengguna yang disimpan server dan hanya diterima sekali.
- Dukung dengan aturan unik di database sehingga dua insert identik tidak bisa sama-sama menang.
Contoh: pengguna mengetuk "Bayar invoice" dua kali di mobile. UI harus memblokir ketukan kedua. Server juga harus menolak permintaan kedua ketika melihat kunci idempoten yang sama, mengembalikan hasil sukses asli alih-alih menagih lagi.
Transisi status yang tidak sinkron
Field status terasa sederhana sampai dua hal mencoba mengubahnya bersamaan. Pengguna klik Approve sementara job otomatis menandai rekaman yang sama Expired, atau dua anggota tim mengerjakan item yang sama di tab berbeda. Kedua pembaruan bisa sukses, tapi status akhir bergantung pada waktu, bukan aturan Anda.
Anggap status sebagai mesin status kecil. Simpan tabel singkat langkah yang diizinkan (mis. Draft -> Submitted -> Approved, dan Submitted -> Rejected). Lalu setiap tulis memeriksa: "Apakah langkah ini diizinkan dari status saat ini?" Jika tidak, tolak daripada menimpa diam-diam.
Optimistic locking membantu menangkap pembaruan usang tanpa memblokir pengguna lain. Tambahkan nomor versi (atau updated_at) dan minta kecocokan saat menyimpan. Jika orang lain mengubah baris setelah Anda memuatnya, pembaruan Anda mempengaruhi nol baris dan Anda bisa menampilkan pesan jelas seperti "Item ini berubah, refresh dan coba lagi."
Polanya sederhana untuk update status:
- Baca status dan versi saat ini
- Validasi transisi
- Update dengan penjaga (WHERE status = ? AND version = ?)
- Increment versi
Juga, tempatkan perubahan status di satu tempat. Jika update tersebar di banyak layar, job latar, dan webhook, Anda akan melewatkan aturan. Letakkan di balik satu fungsi atau endpoint yang menegakkan pengecekan transisi yang sama setiap kali.
Counter dan total yang meleset dari waktu ke waktu
Bug counter paling umum terlihat sepele: aplikasi membaca nilai, menambah 1, lalu menulis kembali. Saat beban tinggi, dua permintaan bisa membaca angka yang sama dan keduanya menulis nilai baru yang sama, sehingga satu kenaikan hilang. Sulit dideteksi karena "biasanya bekerja" saat testing.
Pilih pembaruan atomik daripada baca lalu tulis
Jika sebuah nilai hanya di-increment atau di-decrement, biarkan database yang melakukannya dalam satu pernyataan. Maka database menerapkan perubahan dengan aman meskipun banyak permintaan datang bersamaan.
UPDATE posts
SET like_count = like_count + 1
WHERE id = $1;
Ide yang sama berlaku untuk inventori, view count, retry counter, dan apa pun yang bisa dinyatakan sebagai "baru = lama + delta".
Total meleset saat Anda menyimpan apa yang bisa dihitung
Total sering salah ketika Anda menyimpan angka turunan (order_total, account_balance, project_hours) lalu memperbaruinya dari banyak tempat. Jika Anda bisa menghitung total dari baris sumber (line items, entri buku besar), Anda menghindari kelas bug drift.
Saat Anda harus menyimpan total demi kecepatan, anggap itu sebagai tulis kritis. Gabungkan update baris sumber dan total yang disimpan dalam satu transaksi. Pastikan hanya satu penulis yang bisa memperbarui total yang sama sekaligus (locking, guarded updates, atau path pemilik tunggal). Tambahkan konstraint yang mencegah nilai mustahil (misalnya inventori negatif). Lalu rekonsiliasi sesekali dengan pengecekan latar yang menghitung ulang dan menandai ketidaksesuaian.
Contoh konkret: dua pengguna menambahkan item ke keranjang yang sama bersamaan. Jika setiap permintaan membaca cart_total, menambah harga itemnya, dan menulis kembali, satu penambahan bisa hilang. Jika Anda memperbarui item keranjang dan total keranjang bersama-sama dalam satu transaksi, total tetap benar meskipun ada klik paralel.
Hentikan tabrakan dengan konstraint database terlebih dahulu
Jika Anda ingin lebih sedikit race condition, mulai dari database. Kode aplikasi bisa retry, timeout, atau berjalan dua kali. Konstraint database adalah gerbang akhir yang tetap benar bahkan saat dua permintaan datang bersamaan.
Konstraint unik menghentikan duplikat yang "seharusnya tak pernah terjadi" tapi terjadi: alamat email, nomor pesanan, ID faktur, atau aturan "satu langganan aktif per pengguna". Ketika dua signup mendarat bersamaan, database menerima satu baris dan menolak yang lain.
Foreign keys mencegah referensi rusak. Tanpa mereka, satu permintaan bisa menghapus record induk sementara permintaan lain membuat record anak yang merujuk pada tidak ada apa-apa, meninggalkan row yatim yang sulit dibersihkan.
Check constraints menjaga nilai dalam rentang aman dan menegakkan aturan status sederhana. Misalnya quantity >= 0, rating antara 1 dan 5, atau status terbatas ke set yang diizinkan.
Anggap kegagalan konstraint sebagai hasil yang diharapkan, bukan "error server." Tangkap pelanggaran unik, foreign key, dan check, kembalikan pesan jelas seperti "Email itu sudah digunakan," dan log detail untuk debugging tanpa membocorkan internals.
Contoh: dua orang menekan "Buat order" dua kali saat lag. Dengan konstraint unik pada (user_id, cart_id), Anda tidak mendapatkan dua order. Anda mendapatkan satu order dan satu penolakan yang bersih dan bisa dijelaskan.
Gunakan transaksi dan lock saat satu perubahan harus menang
Beberapa tulis bukan satu pernyataan. Anda baca baris, cek aturan, update status, dan mungkin insert log audit. Jika dua permintaan melakukan itu bersamaan, keduanya bisa lulus cek dan menulis. Itu pola kegagalan klasik.
Bungkus penulisan multi-langkah dalam satu transaksi sehingga semua langkah sukses bersama atau tidak sama sekali. Lebih penting lagi, transaksi memberi Anda tempat untuk mengontrol siapa yang boleh mengubah data yang sama pada saat yang sama.
Saat hanya satu aktor bisa mengedit record pada satu waktu, gunakan row-level lock. Misalnya: lock baris order, konfirmasi masih dalam status "pending", lalu ubah ke "approved" dan tulis entry audit. Permintaan kedua akan menunggu, lalu memeriksa ulang status dan berhenti.
Optimistic vs pessimistic locking
Pilih berdasarkan seberapa sering tabrakan terjadi:
- Optimistic locking: tambah nomor versi (atau updated_at) dan update hanya jika cocok.
- Pessimistic locking: lock baris dulu, lalu baca dan update di dalam transaksi yang sama.
Jaga waktu lock tetap singkat. Lakukan pekerjaan sesedikit mungkin saat mengunci: jangan panggil API eksternal, jangan lakukan kerja file yang lambat, jangan loop besar. Jika Anda membangun alur di tool seperti Koder.ai, buat transaksi hanya untuk langkah database, lalu lakukan sisanya setelah commit.
Langkah demi langkah: perkuat satu alur tulis dari ujung ke ujung
Pilih satu alur yang bisa membuat rugi uang atau kepercayaan saat bertabrakan. Yang umum: buat order, reservasi stok, lalu set status order jadi confirmed.
Tulis langkah persis yang kode Anda lakukan sekarang, berurutan. Spesifik tentang apa yang dibaca, apa yang ditulis, dan apa arti "sukses." Tabrakan bersembunyi di celah antara baca dan tulis yang terlambat.
Jalur penguatan yang bekerja di sebagian besar stack:
- Definisikan hasil buruk yang harus Anda blokir (misalnya: stok negatif, atau dua reservasi untuk SKU yang sama pada order yang sama).
- Tambahkan aturan database yang membuat hasil itu tidak mungkin (mis. CHECK constraint yang mencegah stock < 0, dan UNIQUE constraint pada (order_id, sku) untuk reservasi).
- Bungkus seluruh alur dalam satu transaksi, dan lock baris yang menentukan hasil (mis. lock baris inventori produk sebelum mengurangi stok).
- Lakukan update dalam satu pernyataan bila memungkinkan (mis. "update stock where stock >= qty" sehingga gagal dengan aman).
- Tangani konflik dengan rapi: retry beberapa kali, atau kembalikan pesan "Stok habis, silakan refresh" yang jelas.
Tambahkan satu test yang membuktikan perbaikan. Jalankan dua permintaan bersamaan terhadap produk dan kuantitas yang sama. Pastikan tepat satu order terkonfirmasi, dan yang lain gagal dengan cara terkontrol (tidak ada stok negatif, tidak ada baris reservasi duplikat).
Jika Anda menghasilkan aplikasi dengan cepat (termasuk menggunakan platform seperti Koder.ai), checklist ini tetap layak diterapkan pada beberapa jalur tulis yang paling penting.
Kesalahan umum yang membuat race condition bertahan
Salah satu penyebab terbesar race condition adalah mempercayai UI. Tombol yang dinonaktifkan dan cek sisi-klien membantu, tapi pengguna bisa klik dua kali, refresh, buka dua tab, atau memutar ulang permintaan dari koneksi yang fluktuatif. Jika server tidak idempoten, duplikat lolos.
Bug diam lain: Anda menangkap error database (seperti pelanggaran konstraint unik) tapi meneruskan alur seolah-olah berhasil. Itu sering berubah jadi "pembuatan gagal, tapi kami tetap mengirim email" atau "pembayaran gagal, tapi kami tetap menandai order terbayar." Setelah efek samping terjadi, sulit mundur.
Transaksi panjang juga perangkap. Jika Anda membuka transaksi sambil memanggil email, pembayaran, atau API pihak ketiga, Anda menahan lock lebih lama dari perlu. Itu meningkatkan waktu tunggu, timeouts, dan kemungkinan permintaan saling menunggu.
Mencampur pekerjaan latar dan aksi pengguna tanpa satu sumber kebenaran menciptakan keadaan split-brain. Job retry mengupdate baris sementara pengguna sedang mengeditnya, dan sekarang keduanya mengira mereka penulis terakhir.
Beberapa "perbaikan" yang sebenarnya tidak memperbaiki:
- Pencegahan pengiriman ganda hanya di UI
- Menelan error dan melanjutkan seolah tidak terjadi apa-apa
- Melakukan panggilan jaringan lambat di dalam transaksi
- Membiarkan job dan permintaan pengguna memperbarui state yang sama secara berbeda
- Memperbarui counter dengan baca-modify-write alih-alih update atomik
Jika Anda membangun dengan alat chat-to-app seperti Koder.ai, aturan yang sama berlaku: mintalah konstraint sisi-server dan batasan transaksi yang jelas, bukan hanya penjagaan UI yang lebih rapi.
Pemeriksaan cepat sebelum rilis
Race condition sering muncul hanya di lalu lintas nyata. Pemeriksan sebelum rilis bisa menangkap titik tabrakan paling umum tanpa rewrite besar.
Mulailah dengan database. Jika sesuatu harus unik (email, nomor faktur, satu langganan aktif per pengguna), jadikan itu konstraint unik nyata, bukan aturan cek di aplikasi. Lalu pastikan kode Anda mengantisipasi konstraint bisa gagal dan mengembalikan respons yang jelas dan aman.
Selanjutnya, lihat status. Setiap perubahan status (Draft -> Submitted -> Approved) harus divalidasi terhadap set transisi yang eksplisit. Jika dua permintaan mencoba memindahkan rekaman yang sama, yang kedua harus ditolak atau jadi no-op, bukan menciptakan keadaan di antaranya.
Checklist praktis pra-rilis:
- Pastikan konstraint unik ada untuk setiap aturan yang harus unik, termasuk yang komposit.
- Pastikan setiap endpoint penulisan aman di-retry (kunci idempoten, request ID, atau idempoten alami).
- Bungkus tulis multi-langkah dalam transaksi, terutama saat Anda baca lalu tulis berdasarkan bacaan itu.
- Gunakan lock hanya saat satu perubahan harus menang (mis. satu approval per order).
- Log sinyal konflik (duplicate key error, serialization failure, lock timeout) dan beri alert saat melonjak.
Jika Anda membangun alur di Koder.ai, anggap ini sebagai acceptance criteria: aplikasi yang dihasilkan harus gagal dengan aman saat diulang dan dalam konkurensi, bukan hanya lewat jalur bahagia.
Skenario contoh: mencegah double approval
Dua staf membuka permintaan pembelian yang sama. Keduanya menekan Approve dalam beberapa detik. Kedua permintaan mencapai server.
Apa yang bisa salah berantakan: permintaan di-"approve" dua kali, dua notifikasi dikirim, dan total yang terkait approval (anggaran terpakai, jumlah approval harian) bisa naik dua. Kedua update valid sendiri, tapi mereka bertabrakan.
Berikut rencana perbaikan yang bekerja baik dengan database gaya PostgreSQL.
1) Buat double approval tidak mungkin di database
Tambahkan aturan yang menjamin hanya satu record approval dapat ada untuk sebuah request. Misalnya, simpan approval di tabel terpisah dan terapkan UNIQUE constraint pada request_id. Sekarang insert kedua akan gagal meskipun kode aplikasi bermasalah.
2) Bungkus perubahan state dalam transaksi
Saat approve, lakukan seluruh transisi dalam satu transaksi:
- Lock baris request (atau update dengan kondisi seperti WHERE status = 'pending').
- Verifikasi masih pending.
- Tulis record approval.
- Update status request menjadi approved.
Jika staf kedua datang terlambat, mereka akan melihat 0 row terupdate atau error konstraint unik. Dalam kedua kasus, hanya satu perubahan yang menang.
3) Beri umpan balik UI yang jelas
Setelah perbaikan, staf pertama melihat Approved dan mendapat konfirmasi biasa. Staf kedua melihat pesan ramah seperti: "Permintaan ini sudah disetujui oleh orang lain. Refresh untuk melihat status terbaru." Tidak ada loading tanpa akhir, tidak ada notifikasi ganda, tidak ada kegagalan diam.
Jika Anda menghasilkan flow CRUD di platform seperti Koder.ai (backend Go dengan PostgreSQL), Anda bisa menanamkan pengecekan ini ke dalam action approve sekali lalu pakai ulang pola untuk aksi "hanya satu pemenang" lainnya.
Langkah selanjutnya: jadikan perbaikan race bagian dari rutinitas build
Race condition paling mudah diperbaiki bila Anda memperlakukannya sebagai rutinitas yang bisa diulang, bukan perburuan bug sekali-sekali. Fokus pada beberapa jalur tulis yang paling penting, dan buat mereka benar secara membosankan sebelum memoles hal lain.
Mulai dengan menamai titik tabrakan teratas Anda. Di banyak aplikasi CRUD itu trio yang sama: counter (like, inventori, saldo), perubahan status (Draft -> Submitted -> Approved), dan pengiriman ganda (klik dua kali, retry, jaringan lambat).
Rutinitas yang tahan lama:
- Tuliskan aturan tunggal yang benar untuk setiap alur (mis: sebuah order hanya bisa disetujui sekali, dan hanya dari pending).
- Tambahkan konstraint database dulu (unique keys, foreign keys, check constraints) sehingga database menolak state yang mustahil.
- Tambahkan lock transaksi hanya di tempat satu perubahan harus menang (misalnya, mengunci satu baris saat approval).
- Tambahkan satu test konkurensi kecil per alur kritis, tepat pada kegagalan yang Anda takuti (dua approval, dua increment, dua submit form).
- Tinjau penanganan error sehingga UI menampilkan pesan jelas saat database menolak penulisan yang bertentangan.
Jika Anda membangun di Koder.ai, Planning Mode adalah tempat praktis untuk memetakan setiap alur tulis sebagai langkah dan aturan sebelum menghasilkan perubahan di Go dan PostgreSQL. Snapshot dan rollback juga berguna saat Anda mengirim konstraint baru atau perilaku lock dan ingin cara cepat kembali bila menemukan edge case.
Seiring waktu, ini menjadi kebiasaan: setiap fitur tulis baru mendapat konstraint, rencana transaksi, dan test konkurensi. Begitulah race condition di aplikasi CRUD berhenti menjadi kejutan.
Pertanyaan umum
Apa itu kondisi balapan dalam aplikasi CRUD?
Kondisi balapan terjadi ketika dua permintaan mengubah data yang sama pada waktu yang hampir bersamaan dan waktu menentukan hasilnya. Satu penyimpanan yang valid dapat menimpa yang lain, membuat duplikat, atau memindahkan status dua kali.
Fitur CRUD mana yang paling mungkin mengalami kondisi balapan?
Perhatikan penghitung, inventaris, slot pemesanan, kolom status, dan catatan dengan aturan yang harus unik. Area ini sering memakai pola baca lalu tulis yang gagal saat permintaan tumpang tindih.
Bagaimana cara menghentikan pengguna mengirim formulir dua kali?
Nonaktifkan tombol setelah klik pertama, tetapi juga lindungi server. Kirim satu kunci idempotensi untuk setiap tindakan dan simpan kunci tersebut agar permintaan berulang mengembalikan hasil asli alih-alih membuat catatan kedua.
Bagaimana cara memperbarui penghitung dengan aman?
Gunakan pembaruan database yang mengubah nilai secara langsung, misalnya menambahkan 1 dalam pernyataan SQL. Jangan baca penghitung ke aplikasi, ubah di sana, lalu tulis kembali.
Bagaimana cara mencegah konflik pada perubahan status?
Letakkan perubahan status di balik satu aturan sisi server yang memeriksa status saat ini dan hanya mengizinkan langkah berikutnya yang valid. Tolak transisi yang kedaluwarsa atau tidak valid dengan pesan yang jelas.
Apa itu penguncian optimistis?
Penguncian optimistis menyimpan versi atau stempel waktu bersama catatan. Pembaruan hanya berhasil jika nilainya masih cocok, sehingga aplikasi dapat memberi tahu pengguna bahwa orang lain lebih dulu mengubah catatan tersebut.
Kapan saya harus menggunakan kunci database?
Gunakan transaksi dengan kunci baris ketika satu permintaan harus mengambil keputusan sebelum mengubah beberapa catatan, misalnya mencadangkan stok dan mengonfirmasi pesanan. Jaga pekerjaan yang dikunci tetap singkat dan hindari panggilan API eksternal di dalam transaksi.
Mengapa batasan database penting untuk kondisi balapan?
Tambahkan batasan unik untuk aturan seperti satu email per akun atau satu persetujuan per permintaan. Tambahkan kunci asing dan batasan pemeriksaan untuk referensi serta nilai yang valid. Database kemudian menolak status yang mustahil meskipun dua permintaan tiba bersamaan.
Bagaimana cara mencegah inventaris menjadi negatif?
Jadikan pembaruan stok bersyarat dalam satu transaksi, misalnya kurangi hanya jika stok yang tersisa cukup. Jika pembaruan tidak memengaruhi baris apa pun, beri tahu pembeli bahwa barang tidak tersedia alih-alih mengonfirmasi pesanan yang kelebihan terjual.
Bagaimana cara menguji alur penulisan untuk kondisi balapan?
Jalankan dua permintaan pada waktu yang sama terhadap catatan atau jumlah yang sama, lalu periksa hasilnya. Uji bahwa satu permintaan menang saat diperlukan, konflik mengembalikan respons yang terkontrol, dan database tidak berisi data duplikat atau tidak valid.