Transaksi — SQL

Transaksi memastikan serangkaian operasi database berhasil SEMUA atau GAGAL SEMUA — tidak ada setengah-setengah. Contoh masalah tanpa transaksi: Transfer uang…

Transaksi adalah sekelompok perintah SQL yang diperlakukan sebagai satu kesatuan: semuanya tersimpan, atau gak ada satu pun yang tersimpan. Bayangin transfer di aplikasi m-banking. Saldomu berkurang dan saldo temanmu bertambah, dan dua hal itu harus terjadi bersamaan. Kalau cuma saldomu yang berkurang lalu aplikasinya error, uangnya hilang di tengah jalan.

🧪 Tebakan cepat: Budi (saldo Rp 2.000.000) mentransfer Rp 1.500.000 ke Siti (saldo Rp 1.000.000). Perintah pertama, mengurangi saldo Budi, berhasil. Perintah kedua, menambah saldo Siti, error. Tanpa transaksi, berapa total uang Budi dan Siti sesudahnya: tetap Rp 3.000.000, atau berkurang? Tebak dulu, jawabannya ada di bagian "Tanpa transaksi: berhenti di tengah jalan".

Tabel accounts

Ini tabel dari latihan, ditambah satu aturan dari pelajaran constraint: saldo maksimal Rp 2.000.000, seperti akun dompet digital yang belum di-upgrade. Aturan itu yang nanti bikin satu langkah gagal.

CREATE TABLE accounts (
  id INTEGER PRIMARY KEY,
  name TEXT,
  balance REAL CONSTRAINT saldo_maksimal CHECK (balance <= 2000000)
);
INSERT INTO accounts VALUES (1, 'Budi', 2000000), (2, 'Siti', 1000000);

CONSTRAINT saldo_maksimal cuma memberi nama ke CHECK-nya, supaya pesan error-nya menyebut nama itu.

Transfer dari Budi ke Siti butuh dua perintah:

UPDATE accounts SET balance = balance - 1500000 WHERE id = 1;  -- kurangi saldo Budi
UPDATE accounts SET balance = balance + 1500000 WHERE id = 2;  -- tambah saldo Siti

balance = balance - 1500000 menghitung saldo baru dari saldo yang sekarang. WHERE id = 1 memastikan cuma akun Budi yang berubah.

Tanpa transaksi: berhenti di tengah jalan

Tanpa transaksi, tiap perintah langsung tersimpan permanen begitu selesai. Begini jalannya:

Langkah Budi Siti Total
Awal 2.000.000 1.000.000 3.000.000
UPDATE Budi: berhasil, langsung permanen 500.000 1.000.000 1.500.000
UPDATE Siti: CHECK constraint failed: saldo_maksimal 500.000 1.000.000 1.500.000

Saldo Siti akan jadi Rp 2.500.000, melewati batas, jadi perintah kedua ditolak. Tapi perintah pertama sudah tersimpan. Total uangnya tinggal Rp 1.500.000: Rp 1.500.000 hilang. Itu jawaban tebakannya. Penyebabnya bisa apa saja: aturan yang dilanggar, server mati, atau koneksi putus di antara dua perintah.

BEGIN, COMMIT, ROLLBACK

Tiga perintah ini membungkus beberapa perintah jadi satu transaksi:

BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 500000 WHERE id = 1;
UPDATE accounts SET balance = balance + 500000 WHERE id = 2;
COMMIT;

Kalau satu langkah gagal: ROLLBACK

Transfer Rp 1.500.000 yang tadi, sekarang di dalam transaksi:

Langkah Budi Siti Yang permanen
BEGIN TRANSACTION; 2.000.000 1.000.000 2.000.000 dan 1.000.000
UPDATE Budi: berhasil, belum permanen 500.000 1.000.000 2.000.000 dan 1.000.000
UPDATE Siti: CHECK constraint failed: saldo_maksimal 500.000 1.000.000 2.000.000 dan 1.000.000
ROLLBACK; 2.000.000 1.000.000 2.000.000 dan 1.000.000

Hati-hati di baris ketiga: perintah yang error cuma membatalkan dirinya sendiri. Transaksinya masih terbuka, dan pengurangan saldo Budi masih menunggu. Yang memutuskan nasibnya adalah perintah berikutnya. Kalau kamu tetap menjalankan COMMIT, saldo Budi tersimpan Rp 500.000 dan uangnya tetap hilang. Jadi aturannya: semua lancar, COMMIT; ada yang error, ROLLBACK. Di aplikasi, aturan ini ditulis dengan try dan catch. Di Laravel, DB::transaction(function () { ... }) menjalankan BEGIN, lalu COMMIT kalau semua lancar atau ROLLBACK kalau ada error.

📌 ACID

Empat jaminan yang diberikan transaksi, disingkat ACID:

⚠️ Jebakan yang sering ketemu

TL;DR: Transaksi membungkus beberapa perintah jadi satu: BEGIN TRANSACTION; memulai, COMMIT; menyimpan semuanya sekaligus, ROLLBACK; membatalkan semuanya. Tanpa transaksi, perintah yang sudah jalan tetap tersimpan walau perintah berikutnya gagal, jadi uang bisa hilang di tengah transfer. Perintah yang error cuma membatalkan dirinya sendiri, jadi kalau ada error, kamu yang harus menjalankan ROLLBACK. Hitung saldo dari nilai sekarang (balance - 500000), dan selalu pakai WHERE.

Yang akan kamu pelajari