Dari empat huruf ACID, isolation adalah huruf dengan keragaman terbesar: seberapa jauh pekerjaan transaksi kita terlihat oleh transaksi lain bukan jawaban tunggal, melainkan pilihan bertingkat. MySQL menyediakan empat isolation level — dari yang paling longgar hingga yang paling ketat — dan tiap level membuka atau menutup celah bagi tiga anomali klasik: dirty read, nonrepeatable read, dan phantom read. Pada chapter ini kita bacakan level yang sedang aktif, uji SET SESSION TRANSACTION ISOLATION LEVEL untuk keempat levelnya, buktikan bahwa perubahan itu hanya berlaku untuk sesi yang mengaturnya, lalu petakan anomali lewat skenario dua koneksi dalam tabel waktu.
Menyiapkan Tabel Latihan #
Tabel rekening kembali menjadi arena pengamatan:
DROP DATABASE IF EXISTS belajar_trx;
CREATE DATABASE belajar_trx;
USE belajar_trx;
CREATE TABLE rekening (
id INT AUTO_INCREMENT PRIMARY KEY,
pemilik VARCHAR(50) NOT NULL,
saldo DECIMAL(12,2) NOT NULL
);
INSERT INTO rekening (pemilik, saldo) VALUES ('Budi', 500000.00), ('Siti', 300000.00);
SELECT id, pemilik, saldo FROM rekening ORDER BY id;Output yang Dihasilkan:
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 1 row affected (0.00 sec)
Database changed
Query OK, 0 rows affected (0.00 sec)
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
+----+---------+-----------+
| id | pemilik | saldo |
+----+---------+-----------+
| 1 | Budi | 500000.00 |
| 2 | Siti | 300000.00 |
+----+---------+-----------+
2 rows in set (0.00 sec)Empat Level Isolation dan Level Default #
Isolation level mengatur aturan main saat dua transaksi membaca dan menulis data yang sama. Dari longgar ke ketat, MySQL menyediakan: READ UNCOMMITTED yang membolehkan pembacaan data yang belum di-commit; READ COMMITTED yang hanya membaca data yang sudah di-commit namun melihat versi terbaru di tiap bacaan; REPEATABLE READ yang membekukan tampilan data sejak bacaan pertama dalam transaksi; dan SERIALIZABLE yang menambah kunci sehingga transaksi berjalan bagaikan antrean. Level yang sedang dipakai sesi kita bisa dibaca dari variabel @@transaction_isolation:
SELECT @@transaction_isolation;Output yang Dihasilkan:
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)Nilai REPEATABLE-READ menegaskan level bawaan InnoDB — pilihan yang sudah cukup ketat untuk sebagian besar aplikasi. Perhatikan tanda hubung pada nilainya: nama level di output memakai format REPEATABLE-READ, sementara sintaks SET memakai spasi REPEATABLE READ.
SET SESSION: Mengganti Level untuk Sesi Kita #
Perintah SET SESSION TRANSACTION ISOLATION LEVEL mengubah level isolation untuk sesi saat ini. Kita uji seluruh empat levelnya dalam satu rangkaian dan membaca kembali nilainya setelah tiap penggantian:
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT @@transaction_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT @@transaction_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT @@transaction_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT @@transaction_isolation;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-UNCOMMITTED |
+-------------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED |
+-------------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| SERIALIZABLE |
+-------------------------+
1 row in set (0.00 sec)Empat nilai tampil bergantian — READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE — masing-masing mengikuti perintah SET di atasnya. Kata kunci SESSION berarti pengaturan ini melekat pada sesi yang menjalankannya. Konsekuensinya bisa kita buktikan langsung: koneksi baru yang dibuka setelahnya tidak mewarisi pengaturan itu, melainkan kembali ke level bawaan:
SELECT @@transaction_isolation;Output yang Dihasilkan:
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)Koneksi baru terbaca REPEATABLE-READ — penggantian level di blok sebelumnya tidak bocor keluar sesinya. Selain bentuk SESSION, MySQL juga mengenal SET GLOBAL TRANSACTION ISOLATION LEVEL yang mengubah level bawaan untuk koneksi baru (berbahaya bila dipakai sembarangan karena mengubah perilaku seluruh aplikasi lain), serta SET TRANSACTION ISOLATION LEVEL tanpa scope yang berlaku hanya untuk satu transaksi berikutnya di sesi tersebut. Untuk kode aplikasi, bentuk SET SESSION adalah yang paling lazim: tiap koneksi menyetel levelnya sendiri saat dibuka.
Snapshot Konsisten: Wajah REPEATABLE READ #
Kata snapshot sering muncul berdampingan dengan isolation, dan perlu diluruskan: MySQL tidak memiliki isolation level bernama SNAPSHOT. Yang ada adalah mekanisme consistent snapshot milik REPEATABLE READ — tampilan data yang dibekukan saat transaksi dibuka. Bentuk eksplisitnya bisa kita uji:
START TRANSACTION WITH CONSISTENT SNAPSHOT;
SELECT saldo FROM rekening WHERE id = 1;
COMMIT;Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
+-----------+
| saldo |
+-----------+
| 500000.00 |
+-----------+
1 row in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)START TRANSACTION WITH CONSISTENT SNAPSHOT membuka transaksi dan sekaligus membelikan snapshot pada saat itu — semua SELECT biasa di dalam transaksi akan membaca tampilan yang sama, berapa kali pun dibaca ulang, sepanjang transaksi belum ditutup. Perubahan yang di-commit koneksi lain setelah snapshot dibekukan tetap tidak terlihat oleh transaksi kita. Mekanisme ini dijalankan InnoDB lewat multiversion concurrency control: tiap bacaan bekerja pada salinan versi data tertentu tanpa perlu menunggu kunci penulis, sehingga pembaca dan penulis jarang saling menghalangi.
Tiga Anomali dan Peta Levelnya #
Tiga anomali klasik menjadi alasan level-level itu ada. Tabel berikut memetakan anomali mana yang mungkin terjadi di tiap level — sesuai perilaku InnoDB:
| Isolation level | Dirty read | Nonrepeatable read | Phantom read |
|---|---|---|---|
READ UNCOMMITTED | mungkin | mungkin | mungkin |
READ COMMITTED | tidak | mungkin | mungkin |
REPEATABLE READ | tidak | tidak | tidak (khusus InnoDB) |
SERIALIZABLE | tidak | tidak | tidak |
Catatan penting ada di baris REPEATABLE READ: standar SQL mengizinkan phantom read pada level ini, tetapi implementasi InnoDB mencegahnya — SELECT biasa terlindungi snapshot, sedangkan SELECT ... FOR UPDATE terlindungi next-key lock yang mengunci rentang baris. Level SERIALIZABLE memperketat lagi dengan menambahkan kunci shared pada pembacaan biasa, sehingga transaksi penulis harus menunggu — keketatan penuh dengan harga konkurensi yang lebih rendah.
Skenario Dua Koneksi dalam Tabel Waktu #
Anomali hanya hidup ketika dua koneksi bekerja bersamaan, jadi kita petakan satu per satu lewat tabel waktu. Skenario dirty read pada level READ UNCOMMITTED — satu-satunya level yang membolehkannya:
| Waktu | Koneksi A | Koneksi B | Yang terjadi |
|---|---|---|---|
| t1 | START TRANSACTION; | A membuka transaksi | |
| t2 | UPDATE ... SET saldo = saldo + 100000 WHERE id = 1; | saldo tercatat Rp600.000,00 di A, belum di-commit | |
| t3 | SELECT saldo ... WHERE id = 1; | B membaca Rp600.000,00 — dirty read | |
| t4 | ROLLBACK; | saldo kembali Rp500.000,00 | |
| t5 | angka yang dibaca B tidak pernah ada |
Laporan koneksi B di t3 memakai data yang sedang berubah dan akhirnya dibatalkan — keputusan bisnis yang diambil dari angka itu menjadi keputusan atas data hantu. Naik ke READ COMMITTED, skenario yang sama berubah: bacaan B di t3 tetap melihat Rp500.000,00 karena transaksi A belum menutup; celahnya pindah menjadi nonrepeatable read — bila koneksi A menjalankan UPDATE lalu COMMIT di antara dua bacaan koneksi B, dua bacaan itu menghasilkan angka berbeda (Rp500.000,00 lalu Rp600.000,00) meski B tidak pernah menulis apa pun. Pada level REPEATABLE READ, snapshot koneksi B memastikan kedua bacaan konsisten; anomali terakhir, phantom read, menyisakan diri di READ COMMITTED lewat query rentang — B menjalankan SELECT COUNT(*) dua kali, dan di sela-selanya A menyisipkan rekening baru, sehingga hitungan B melonjak tanpa B menulis apa pun.
Membersihkan Database Latihan #
Rangkaian latihan selesai dan database latihan kita jatuhkan kembali:
DROP DATABASE belajar_trx;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)Referensi #
- Transaction Isolation Levels — MySQL 8.4 Reference Manual
- Consistent Nonlocking Reads — MySQL 8.4 Reference Manual
- START TRANSACTION, COMMIT, and ROLLBACK Statements — MySQL 8.4 Reference Manual
Empat level isolation beserta anomali-nya kini terpetakan, SET SESSION terbukti hanya berlaku untuk sesinya, dan wajah snapshot dari REPEATABLE READ sudah kita lihat dari dekat. Isolation menjelaskan sebagian cerita tentang transaksi yang berjalan bersamaan; sisa ceritanya ada di mekanisme yang bekerja di balik layar setiap kali dua transaksi memperebutkan baris yang sama: locking. Chapter berikutnya membedah row lock InnoDB, SELECT ... FOR UPDATE, dan LOCK TABLES.