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;
BEGIN TRANSACTION;memulai transaksi. CukupBEGIN;juga boleh, dan di MySQL biasa ditulisSTART TRANSACTION;.- Sesudah
BEGIN, perubahan dariUPDATEbelum permanen. Koneksi yang menjalankannya sudah melihat saldo baru, tapi koneksi lain masih melihat saldo lama. COMMIT;menyimpan semua perubahan sejakBEGINsecara permanen, sekaligus. Hasilnya: Budi Rp 1.500.000, Siti Rp 1.500.000. Ini persis yang diminta latihan.ROLLBACK;kebalikannya: membatalkan semua perubahan sejakBEGIN, seolah gak pernah terjadi.
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:
- Atomicity: semua atau gak sama sekali. Ini yang kita pakai di transfer tadi.
- Consistency: sesudah transaksi, data tetap memenuhi semua aturan, seperti
saldo_maksimal. - Isolation: transaksi yang jalan bersamaan gak saling melihat perubahan yang belum di-
COMMIT. Seberapa ketat pemisahannya disebut isolation level. SQLite paling ketat (serializable, satu penulis dalam satu waktu), MySQL bawaannyaREPEATABLE READ, PostgreSQL bawaannyaREAD COMMITTED. - Durability: yang sudah di-
COMMITgak hilang, walau server mati sesudahnya.
⚠️ Jebakan yang sering ketemu
COMMITpadahal ada yang error. Perintah yang sukses tetap tersimpan. Kalau ada yang error,ROLLBACK.- Lupa
COMMIT. Selama belum di-COMMIT, perubahannya belum permanen. Kalau koneksinya ditutup, semuanya dibatalkan. - Mengetik saldo hasil akhirnya langsung.
SET balance = 1500000cuma benar kalau saldo awalnya persis seperti yang kamu kira. Hitung dari saldo yang sekarang:balance - 500000. Latihannya mengecek bentuk ini. - Lupa
WHERE.UPDATE accounts SET balance = balance - 500000tanpaWHEREmengurangi saldo semua akun.
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.