Transaction di Postgres
Transaksi di PostgreSQL adalah unit kerja logis yang terdiri dari satu atau lebih pernyataan SQL yang dijalankan sebagai satu kesatuan. Tujuan utamanya adalah untuk menjaga konsistensi, isolasi, dan integritas data.
๐ Konsep Transaksi di PostgreSQL
1. ACID
Transaksi harus memenuhi sifat ACID:
Atomicity: Semua pernyataan dalam transaksi berhasil semua atau dibatalkan semua.
Consistency: Data tetap konsisten sebelum dan sesudah transaksi.
Isolation: Transaksi tidak terlihat oleh transaksi lain sampai selesai.
Durability: Setelah commit, data tersimpan permanen.
2. Perintah Dasar
๐ Apa itu FOR UPDATE
?
FOR UPDATE
?FOR UPDATE
digunakan untuk mengunci baris yang dipilih dalam transaksi agar tidak bisa diubah oleh transaksi lain sampai transaksi selesai (commit/rollback).
Tujuannya:
Mencegah kondisi race condition (misalnya dua pengguna mengedit data yang sama).
Memastikan data yang dibaca tidak berubah sebelum transaksi selesai.
๐ฏ Contoh dan Ilustrasi
1. Setup Tabel
2. Simulasi Transaksi tanpa FOR UPDATE
FOR UPDATE
Terminal 1:
Terminal 2 (dijalankan sebelum commit Terminal 1):
Masalah: Kedua transaksi menganggap saldo awal 1000 dan memperbarui berdasarkan data yang sudah kadaluarsa โ terjadi inconsistency.
3. Simulasi Transaksi dengan FOR UPDATE
FOR UPDATE
Terminal 1:
Terminal 2:
Keuntungan: Data tidak bisa dibaca dan diproses oleh transaksi lain sebelum transaksi pertama selesai โ race condition dihindari.
๐งช Praktek Langsung: Transfer Saldo
Misal: Transfer 100 dari Alice ke Bob
Jika terjadi error, bisa langsung:
๐ง Kesimpulan
Transaksi
Sekumpulan perintah SQL yang dieksekusi sebagai satu kesatuan
BEGIN/COMMIT
Memulai dan menyelesaikan transaksi
ROLLBACK
Membatalkan transaksi
FOR UPDATE
Mengunci baris yang dipilih untuk mencegah konflik antar transaksi
โ ๏ธ Apa Itu Deadlock?
Deadlock terjadi ketika dua transaksi saling menunggu satu sama lain untuk melepaskan kunci, sehingga tidak ada yang bisa lanjut.
๐ Ilustrasi Kasus Deadlock
Misalkan kita punya tabel akun
yang sama:
๐งช Simulasi Deadlock dengan FOR UPDATE
FOR UPDATE
Transaksi 1 (T1):
Transaksi 2 (T2):
๐ Hasil:
T1 mengunci Alice โ tunggu Bob
T2 mengunci Bob โ tunggu Alice
Keduanya saling tunggu โ deadlock
PostgreSQL akan memilih satu untuk dibatalkan (
ERROR: deadlock detected
)
๐ ๏ธ Kenapa Bisa Deadlock Walau Pakai FOR UPDATE
?
FOR UPDATE
?Karena FOR UPDATE
mengunci baris secara eksklusif. Kalau dua transaksi mengunci dengan urutan berbeda, maka bisa saling tunggu. Urutan pengambilan kunci itu penting.
โ
Solusi: Gunakan FOR NO KEY UPDATE
FOR NO KEY UPDATE
โ Apa Itu FOR NO KEY UPDATE
?
FOR NO KEY UPDATE
?FOR NO KEY UPDATE
adalah varian lebih ringan dariFOR UPDATE
.Mengunci baris hanya untuk update nilai kolom, tanpa mengizinkan update kunci (misalnya kolom primary key).
Ini mengurangi kemungkinan deadlock karena kunci yang digunakan tidak terlalu agresif.
๐ Perbandingan Lock Mode
FOR UPDATE
Mengunci baris untuk update penuh (termasuk kunci)
FOR NO KEY UPDATE
Mengunci baris untuk update non-kunci (lebih ringan)
FOR SHARE
Hanya baca data, bisa dibaca transaksi lain
FOR KEY SHARE
Bisa dibaca dan referensi foreign key, tapi tidak bisa dihapus/dikunci penuh
๐งช Simulasi dengan FOR NO KEY UPDATE
FOR NO KEY UPDATE
Jika transaksi hanya ingin update saldo (bukan id
), maka lebih aman:
T1:
T2:
โ ๏ธ Hasil:
Deadlock masih mungkin terjadi kalau urutan ambil lock-nya berbeda, meskipun lebih jarang.
Maka kunci solusi utamanya tetap: urutkan pengambilan kunci secara konsisten!
โ
Best Practice Hindari Deadlock
Selalu akses resource dalam urutan yang sama (misal: urut berdasarkan
id
ASC).Gunakan lock mode serendah mungkin (
FOR NO KEY UPDATE
lebih baik dariFOR UPDATE
).Gunakan timeout / pengecekan deadlock dan rollback otomatis jika perlu.
๐ Kesimpulan
FOR UPDATE
kuat tapi agresif โ rawan deadlock jika resource diakses tidak konsisten.FOR NO KEY UPDATE
lebih ringan โ cocok jika hanya update kolom non-kunci.Urutan pengambilan kunci lebih penting dari jenis lock-nya.
๐ Apa Maksudnya "Pengambilan Kunci Secara Konsisten"?
Artinya: semua transaksi yang mengakses banyak baris/data harus mengunci data dalam urutan yang sama, misalnya:
berdasarkan
id
ASCberdasarkan abjad nama
urutan waktu tertentu
โ Jika Transaksi A mengunci data dengan urutan A โ B dan Transaksi B mengunci data dengan urutan B โ A, โ ๏ธ maka potensi deadlock sangat tinggi.
โ Jika semua transaksi selalu mengunci A โ B, maka tidak akan ada saling tunggu silang.
๐ Contoh Deadlock karena Kunci Tidak Konsisten
Misal tabel akun
:
Transaksi A
Transaksi B
๐ Keduanya saling tunggu โ Deadlock!
โ
Solusi: Ambil Kunci Berdasarkan Urutan Tetap
Cara Aman:
Jadi, transaksi A dan B:
โ Hasil: tidak ada saling tunggu silang, karena kedua transaksi:
mengakses
id = 1
lebih dulubaru
id = 2
berikutnya
๐งช Contoh Praktis: Transfer Saldo Aman
๐ง Ringkasan Tips
๐ Gunakan urutan tetap
Gunakan ORDER BY
berdasarkan id
, nama
, atau kriteria stabil lainnya
๐ซ Jangan kunci berbeda-beda urutan
Hindari transaksi A โ B dan B โ A
โ๏ธ Gunakan LEAST
/ GREATEST
Untuk menentukan siapa dikunci lebih dulu secara deterministik
๐ Gabungkan dalam satu query
Semakin sedikit query terpisah, semakin kecil peluang deadlock
๐ก Gunakan lock ringan (NO KEY UPDATE
)
Kalau tidak perlu ubah PK atau referensi, pakai lock lebih ringan
Last updated