Transaksi dan Lock

Telusuri atomisitas dengan BEGIN/COMMIT/ROLLBACK, rollback sebagian dengan SAVEPOINT, AUTOCOMMIT, dan konsep lock, tingkat isolasi, serta properti ACID — semuanya dengan diagram dan contoh kode read-only.

Artikel ini dibangun dari diagram dan kode read-only

Transaksi baru benar-benar hidup di RDBMS sungguhan di mana banyak pengguna mengakses database pada saat yang sama, dan konsol in-browser kursus ini tidak bisa mereproduksi perilaku itu secara setia.

Itulah sebabnya artikel ini tidak memiliki latihan yang bisa dijalankan — baca blok code di setiap bagian sebagai contoh yang dimaksudkan untuk dijalankan di RDBMS sungguhan (MySQL / PostgreSQL / Oracle, dll.).

Apa itu transaksi — memperlakukan beberapa pernyataan SQL sebagai satu unit

Transaksi adalah cara untuk memperlakukan beberapa pernyataan SQL sebagai satu unit tunggal: jika semua berhasil, mereka di-commit bersama; jika ada yang salah di tengah, mereka semua di-rollback bersama.

Ini penting untuk setiap proses di mana hanya separuh pekerjaan yang berhasil akan menjadi masalah — pikirkan transfer bank (satu UPDATE untuk debit, satu untuk kredit), atau mengonfirmasi order online (kurangi stok, sisipkan baris order).

Bentuk dasarnya adalah BEGIN; (mulai) → beberapa pernyataan → COMMIT; (konfirmasi) / ROLLBACK; (batalkan).

Blok code di artikel ini memakai tabel account yang merepresentasikan rekening bank. Tiga kolomnya adalah account_id, owner (nama pemilik rekening), dan balance. Asumsikan data awal berikut saat membaca.

account_idownerbalance
1Alice1000
2Bob500
3Carol800
4Dave1200

Atomisitas — BEGIN ... COMMIT / ROLLBACK

Ketika kamu BEGIN; lalu COMMIT;, setiap perubahan di antara dua pernyataan itu diterapkan bersama.

Jalankan ROLLBACK; sebagai gantinya dan setiap perubahan setelah BEGIN; dibatalkan, mengembalikan database ke kondisinya sebelum transaksi dimulai.

Properti "semua atau tidak sama sekali" ini disebut atomisitas — artinya unit yang tidak bisa dibagi menjadi bagian yang lebih kecil.

Ketika sesuatu seperti pelanggaran constraint CHECK terjadi di tengah transaksi, langkah standarnya adalah ROLLBACK; untuk dengan aman membatalkan semuanya.

Percabangan COMMIT / ROLLBACK
BEGINcoba perubahancek hasilCOMMITkonfirmasi perubahanROLLBACKkembali ke awalsemuanya baikbatal / error
Setelah BEGIN, COMMIT mengonfirmasi perubahan; ROLLBACK mengembalikan semuanya ke kondisi sebelum BEGIN. Bahkan setelah pelanggaran CHECK, ROLLBACK dengan aman membatalkan semuanya.
-- Transfer: Alice -> Bob, 100 (dimaksudkan untuk dijalankan di RDBMS sungguhan)
BEGIN;
UPDATE account SET balance = balance - 100 WHERE owner = 'Alice';
UPDATE account SET balance = balance + 100 WHERE owner = 'Bob';
COMMIT;   -- kedua UPDATE dikonfirmasi pada saat yang sama

-- Batalkan: berubah pikiran / ada yang salah
BEGIN;
UPDATE account SET balance = balance - 300 WHERE owner = 'Alice';
UPDATE account SET balance = balance + 300 WHERE owner = 'Bob';
ROLLBACK; -- kedua UPDATE dibuang bersama

SAVEPOINT — me-rollback hanya sebagian transaksi

SAVEPOINT name; menaruh penanda di tengah transaksi, dan ROLLBACK TO name; lalu me-rollback hanya sampai penanda itu.

Perubahan yang dibuat sebelum penanda tetap ada, jadi kamu bisa melanjutkan dengan operasi lain dan COMMIT; di akhir.

Pemakaian khas: proses multi-langkah seperti "konfirmasi order → berikan poin → kurangi stok", di mana hanya pengurangan stok yang gagal dan kamu ingin mencoba ulang langkah itu saja. Lebih halus dari membuang seluruh transaksi dengan ROLLBACK;.

SAVEPOINT dan ROLLBACK TO — rollback sebagian
BEGINUPDATEAlice -100SAVEPOINT sp1penanda di siniUPDATEBob -100ROLLBACK TO sp1batalkan bagian Bob sajaCOMMITkonfirmasi hanya Alice -100batalkanlanjut
Tanam penanda dengan SAVEPOINT dan batalkan hanya perubahan setelahnya dengan ROLLBACK TO. Perubahan sebelum penanda tetap ada dan bisa dikonfirmasi dengan COMMIT di akhir.
-- Batalkan hanya update kedua dengan SAVEPOINT (dimaksudkan untuk dijalankan di RDBMS sungguhan)
BEGIN;
UPDATE account SET balance = balance - 100 WHERE owner = 'Carol';
SAVEPOINT sp1;
UPDATE account SET balance = balance - 100 WHERE owner = 'Dave';
ROLLBACK TO sp1;   -- batalkan hanya Dave (Carol -100 tetap)
COMMIT;            -- konfirmasi hanya Carol -100

AUTOCOMMIT — secara default, setiap pernyataan meng-commit dirinya sendiri

Ketika kamu menjalankan UPDATE atau INSERT mandiri tanpa menulis BEGIN; lebih dulu, setiap pernyataan di-commit secara otomatis sendiri.

Itu disebut AUTOCOMMIT — mode default di mana setiap pernyataan di-commit segera setelah dijalankan.

Untuk meng-commit atau membatalkan beberapa pernyataan sebagai satu unit, kamu harus secara eksplisit memulai transaksi dengan BEGIN;.

AUTOCOMMIT vs. transaksi eksplisit
Tanpa BEGIN(AUTOCOMMIT)Dengan BEGINtransaksi eksplisitUPDATEcommit langsungUPDATEbelum di-committidak bisa dibatalkanCOMMIT untuk konfirmasiROLLBACK untuk batalkan
Tanpa BEGIN, setiap pernyataan di-commit saat dijalankan. Dengan BEGIN, semua sampai COMMIT menjadi satu unit yang bisa kamu rollback bersama.

Lock dan deadlock — dasar-dasar konkurensi

Database di dunia nyata diakses oleh banyak pengguna pada saat yang sama. Misal Alice memiliki saldo 1000, dan dua toko (X dan Y) mencoba menagih dia pada saat yang sama — keduanya mungkin membaca "1000" dan menguranginya, dan salah satu debit itu hilang tanpa suara.

Pertahanan terhadap ini adalah lock: sementara transaksi satu pengguna menyentuh sebuah baris, siapa pun yang mencoba menyentuh baris yang sama harus menunggu. Yang pertama masuk mengunci baris, dan yang kedua menunggu.

Tetapi ada sisi lain: jika user A mengunci akun dalam urutan "akun 1 → akun 2" dan user B mengunci mereka dalam urutan "akun 2 → akun 1", mereka akan saling menunggu lock satu sama lain selamanya. Itu adalah deadlock. Perbaikan klasiknya adalah selalu memperoleh lock dalam urutan yang sama (misal, selalu berdasarkan account_id naik). Jika deadlock memang terjadi, database akan secara paksa membatalkan salah satu transaksi untuk memecahkan siklus.

Lock dan jalan buntu-nya (deadlock)
User Amengunci akun 1User Bmengunci akun 2A meminta akun 2dan menungguB meminta akun 1dan menungguDeadlockkeduanya menunggu selamanyaDB secara paksa membatalkansalah satunya
Sementara satu pengguna meng-update baris, baris itu di-lock dan pengguna lain harus menunggu. Jika dua transaksi masing-masing memegang apa yang dibutuhkan yang lain, keduanya menunggu selamanya — deadlock.

Tingkat isolasi dan ACID — ringkasan terminologi

Tingkat isolasi mengontrol seberapa banyak pekerjaan yang sedang berlangsung dari transaksi konkuren lain yang bisa dilihat oleh transaksi tertentu.

Setting lebih lemah (seperti READ COMMITTED) lebih cepat tetapi membiarkan kamu melihat lebih banyak perubahan orang lain, sementara setting lebih kuat (seperti SERIALIZABLE) lebih aman tetapi memaksa lebih banyak menunggu.

Bersama dengan atomisitas (A), konsistensi (C), isolasi (I), dan durabilitas (D — begitu COMMIT terjadi, data tetap di disk dan bertahan dari crash atau mati listrik), keempat ini membentuk properti ACID.

Perilaku tepat lock dan tingkat isolasi bervariasi per produk, jadi ketika kamu membangun sesuatu untuk produksi, periksa spesifikasi database yang kamu pakai.

ACIDArti
A — AtomicityPernyataan antara BEGIN dan COMMIT semuanya diterapkan atau tidak sama sekali.
C — ConsistencyConstraint CHECK, foreign key, dan aturan integritas lain tetap berlaku sebelum dan sesudah transaksi.
I — IsolationPekerjaan yang sedang berlangsung dari transaksi konkuren lain disembunyikan sesuai tingkat isolasi.
D — DurabilityHasil yang ter-commit tetap di disk dan bertahan dari mati listrik atau crash.
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Apa nama properti yang memperlakukan dua UPDATE (debit + kredit) dari transfer uang sebagai satu unit — meng-commit mereka bersama jika keduanya berhasil, atau membatalkan keduanya jika ada yang gagal di tengah?

Soal 2Apa yang terjadi pada tabel ketika kamu menjalankan BEGIN; UPDATE ...; UPDATE ...; ROLLBACK;?

Soal 3Apa yang terjadi ketika kamu menjalankan satu UPDATE sendiri, tanpa menulis BEGIN; lebih dulu?