Amati anomali isolasi
Telusuri lost update, write skew, snapshot, dan konflik serialisasi dengan urutan langkah yang konkret.
Pertanyaan
Urutan langkah seperti apa yang bikin dua transaksi yang benar menghasilkan data yang salah?
Setelah baca ini, kamu bisa menggambar riwayat dua transaksi berselang-seling, menamai anomali yang muncul, dan menyebut tingkat isolasi atau pengaman yang mencegahnya.
Prasyarat dan contoh
Kamu sudah bisa menyatakan invarians (M05.01) dan paham BEGIN, COMMIT, dan ROLLBACK.
Aplikasi klinik: minimal satu dokter harus siaga setiap saat. Ada dua dokter siaga, Ani dan Budi. Keduanya membuka aplikasi dan menekan "ambil cuti" pada detik yang sama. Kedua transaksi menghitung dokter siaga, melihat 2, dan menyimpulkan "aman, masih ada satu lagi". Keduanya commit. Hasil: nol dokter siaga.
Nggak ada baris yang ditulis dua kali, jadi nggak ada konflik yang kelihatan. Itu yang bikin anomali ini licin.
Mekanisme
Cara membaca riwayat. Tulis langkah dua transaksi, T1 dan T2, dalam urutan waktu. Tanya: apakah ada urutan serial (T1 dulu lalu T2, atau sebaliknya) yang menghasilkan keadaan akhir sama? Kalau nggak ada, itu anomali.
Lost update. Dua transaksi membaca nilai yang sama, lalu menimpa.
T1: baca saldo = 100
T2: baca saldo = 100
T1: tulis saldo = 100 + 50 -- 150
T2: tulis saldo = 100 - 30 -- 70 (setoran T1 hilang)
Hasil serial seharusnya 120. Dengan READ COMMITTED biasa, pola baca di aplikasi lalu tulis nilai
absolut bisa kehilangan update. Penangkalnya ada di M05.03: SET saldo = saldo + 50, kunci baris,
atau versi.
Non-repeatable read dan phantom. Dalam satu transaksi, query yang sama menghasilkan hasil
beda karena transaksi lain commit di antaranya (baris berubah, atau baris baru muncul).
READ COMMITTED mengizinkan ini. REPEATABLE READ mencegah baris berubah, dan menurut standar
SQL masih boleh phantom, walau banyak engine (termasuk PostgreSQL) lebih ketat dari standar.
Snapshot isolation. Setiap transaksi melihat salinan konsisten dari saat transaksi dimulai.
Pembaca nggak memblokir penulis. Dua transaksi yang menulis baris yang sama: yang commit kedua
ditolak ("first committer wins"). Di PostgreSQL, REPEATABLE READ berperilaku seperti snapshot.
Write skew. Dua transaksi membaca himpunan data yang sama, lalu menulis baris berbeda berdasarkan apa yang dibaca. Snapshot isolation nggak mendeteksinya karena nggak ada baris yang ditulis dua kali.
T1: hitung siaga = 2 T2: hitung siaga = 2
T1: UPDATE ani SET siaga = false
T2: UPDATE budi SET siaga = false
T1: COMMIT T2: COMMIT -- siaga = 0
Serializable. Hasil harus setara dengan suatu urutan serial. PostgreSQL mengimplementasikan
Serializable Snapshot Isolation: transaksi jalan seperti snapshot, tapi engine melacak dependensi
baca-tulis dan membatalkan salah satu transaksi saat menemukan pola yang berbahaya. Yang
dibatalkan menerima error 40001 (serialization_failure).
Ringkasan (perilaku bervariasi per engine, cek dokumentasinya):
| Anomali | READ COMMITTED | REPEATABLE READ / snapshot | SERIALIZABLE | | --- | --- | --- | --- | | Lost update (baca lalu tulis nilai absolut) | mungkin | ditolak saat commit di PostgreSQL | dicegah | | Non-repeatable read | mungkin | dicegah | dicegah | | Write skew | mungkin | mungkin | dicegah |
Saat rancangan ini gagal
- Mengira default aman. Default PostgreSQL dan Oracle adalah
READ COMMITTED, MySQL InnoDBREPEATABLE READ. Keduanya mengizinkan anomali yang berbeda. - Menaikkan isolation tanpa retry.
SERIALIZABLEyang melempar40001tanpa loop retry mengubah anomali diam-diam jadi error terang-terangan. Lebih jujur, tapi tetap rusak buat pengguna. - Tabel hot di
SERIALIZABLE. Pada 500 transaksi/detik yang menyentuh stok konser yang sama, tingkat pembatalan bisa tinggi dan throughput efektif turun. Kunci eksplisit atau satuUPDATEatomik sering lebih murah. - Menguji anomali di mesin lokal. Race muncul di bawah konkurensi nyata. Satu pengguna di laptop nggak memicunya.
- Menganggap snapshot sama dengan serializable. Write skew membuktikan keduanya beda.
Latihan
Dua pelanggan memesan kursi dengan aturan "satu pelanggan maksimal 2 kursi per konser".
Pelanggan P sudah punya 1 kursi. P membuka dua tab dan menekan "pesan" di keduanya. Database
REPEATABLE READ (snapshot). Kode: hitung kursi P, kalau < 2 insert baris pesanan baru.
Gambar riwayatnya, sebutkan anomalinya, dan beri dua cara memperbaikinya.
Lihat pembahasan
Riwayat:
T1: hitung kursi P = 1 T2: hitung kursi P = 1
T1: INSERT pesanan (kursi 14)
T2: INSERT pesanan (kursi 15)
T1: COMMIT T2: COMMIT -- P punya 3 kursi
Anomalinya write skew (varian phantom): kedua transaksi membaca himpunan yang sama dan menyisipkan baris berbeda. Snapshot isolation nggak melihat konflik karena nggak ada baris yang ditulis dua kali.
Perbaikan:
- Naikkan transaksi ini ke
SERIALIZABLEdan retry pada40001. Salah satu tab akan dibatalkan, diulang, lalu melihatkursi P = 2dan ditolak dengan pesan yang benar. - Kunci baris yang jadi "penjaga" aturan:
SELECT ... FROM pelanggan WHERE id = P FOR UPDATEdi awal transaksi (atau simpanjumlah_kursidi baris pelanggan dan naikkan dengan update bersyarat). Dua transaksi untuk P jadi berurutan.
Opsi 2 lebih murah kalau kontensi per pelanggan rendah, opsi 1 lebih umum kalau banyak aturan serupa. Keduanya perlu penanganan error yang diterjemahkan jadi pesan pengguna.
Terkait
- M05.01 Nyatakan invarians bisnis adalah aturan yang dilanggar oleh anomali di sini.
- M05.03 Koordinasikan perubahan konkuren membahas kunci dan pembaruan atomik sebagai perbaikan.
- Lab L05 menyimulasikan beberapa anomali terpilih dengan riwayat langkah demi langkah.
Catatan
- Asumsi: PostgreSQL sebagai contoh utama. Nama dan perilaku tingkat isolasi berbeda di MySQL, Oracle, dan SQL Server.
- Yang nggak dibahas: isolation level berbasis lock (2PL) secara rinci, dan konsistensi lintas replika (M08).
- Perilaku engine spesifik bisa berubah antar versi. Selalu cek dokumentasi versi yang kamu pakai.
- Terakhir ditinjau: 26 Oktober 2026.