Lompat ke konten
19 menit bacamateri 26 dari 96

Amati anomali isolasi

Telusuri lost update, write skew, snapshot, dan konflik serialisasi dengan urutan langkah yang konkret.

Ditinjau 26 Oktober 2026

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 InnoDB REPEATABLE READ. Keduanya mengizinkan anomali yang berbeda.
  • Menaikkan isolation tanpa retry. SERIALIZABLE yang melempar 40001 tanpa 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 satu UPDATE atomik 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:

  1. Naikkan transaksi ini ke SERIALIZABLE dan retry pada 40001. Salah satu tab akan dibatalkan, diulang, lalu melihat kursi P = 2 dan ditolak dengan pesan yang benar.
  2. Kunci baris yang jadi "penjaga" aturan: SELECT ... FROM pelanggan WHERE id = P FOR UPDATE di awal transaksi (atau simpan jumlah_kursi di 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

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.

Isi · System Design