Pelajaran modul (2/4)
Kondisi balapan
Memahami bagaimana database bekerja secara terpisah pada satu terminal adalah hal yang sederhana, namun dalam skenario web nyata akan ada ratusan proses "Node/PHP/Go" yang mengirimkan permintaan secara bersamaan. Di sinilah Kondisi Balapan yang terkenal lahir.
Masalah "Pembaruan Hilang".
Pembaruan Hilang terjadi ketika dua utas membaca baris lama yang sama, menghitungnya di server JavaScript dan kemudian mengirim kembali UPDATE untuk menyimpan hasilnya.
Skenario:
- Produk #5 ada 10 unit.
- Pengguna A membeli satu (Server A membaca "10", menghitung "9").
- Dalam milidetik yang sama, pengguna B membeli yang lain sebelum pembelian A menyelesaikan fase COMMIT.
- Server B juga membaca "10", menghitung "9".
- Server A mengirimkan
UPDATE: set quantity = 9. - Server B mengirimkan
UPDATE: set quantity = 9. - Keduanya berpikir mereka berhasil mengurangi jumlahnya. Tapi nilai akhirnya seharusnya 8 unit! Pembelian hantu telah hilang.
Solusi tanpa transaksi berat (Atomic Updates)
Daripada membaca dan menghitung di luar, biarkan DB melakukannya selama pembaruan itu sendiri, yang selalu tersinkronisasi.
-- Wrong
UPDATE products SET stock = 9 WHERE id = 5;
-- Correct and natively thread-safe
UPDATE products SET stock = stock - 1 WHERE id = 5;Anomali yang lebih ekstrim (Dirty Reads & Phantoms)
- Bacaan Kotor: Anda membaca data sementara orang lain yang belum dikonfirmasi oleh COMMIT (dan bisa tiba-tiba masuk ke ROLLBACK sehingga membuat Anda tidak valid).
- Pembacaan Hantu: Anda melakukan pemindaian terhadap semua baris, sementara thread kedua menyisipkan catatan baru, kemudian Anda melakukan pemindaian lagi pada transaksi yang sama dan secara ajaib Anda menemukan catatan baru muncul entah dari mana, membahayakan laporan keuangan yang dihitung.
Ubah data pelanggan secara atomik untuk manipulasi string kecil.\nMisalkan kita ingin mengganti nama 'kota' pelanggan untuk menambahkan tanda bintang. \nLakukan dengan memanfaatkan nilai baris itu sendiri untuk nilai yang memiliki id=10, menggabungkan ' - Lama' ke nilai saat ini (Gunakan pipa rangkaian postgres' || ).
Tunjukkan petunjuk
UPDATE pelanggan SET kota = kota || ' - Lama' WHERE id = 10;
Solusi tersedia setelah 3 upaya
Pembaruan klasik yang hilang terjadi pada pembayaran dan harga.\nMisalkan ada kenaikan harga darurat: Naikkan 'unit_price' pada tabel 'order_items' (untuk produk 1 dari pesanan 1) sebesar 20% secara atomik, yaitu mengalikannya * 1,2 alih-alih memasukkan harga baru yang telah dihitung secara manual di JS.
Tunjukkan petunjuk
UPDATE order_items SET unit_price = unit_price * 1.2 DIMANA order_id = 1 DAN product_id = 1;
Solusi tersedia setelah 3 upaya