Deadlock database terjadi ketika dua transaksi atau lebih saling menunggu sumber daya (lock) yang sedang dipegang oleh transaksi lain, sehingga proses terhenti secara permanen hingga sistem atau administrator melakukan intervensi. Mengatasi deadlock memerlukan identifikasi akar permasalahan pada pola akses data, perbaikan struktur indeks, serta penyesuaian logika transaksi pada aplikasi.
Langkah tercepat untuk merespons deadlock yang sedang aktif adalah mengidentifikasi proses yang terlibat menggunakan perintah pemantauan bawaan database, lalu memutus (terminate) salah satu transaksi menggunakan perintah kill atau membiarkan mekanisme automatic deadlock detector dari sistem manajemen basis data (DBMS) memilih korban (victim) untuk dibatalkan.
Metriks Perbandingan Strategi Penanganan Deadlock
| Strategi | Tingkat Kompleksitas | Dampak Performa | Skenario Penggunaan Terbaik |
|---|---|---|---|
| Automatic Victim Selection | Rendah | Minimal | Sistem standar dengan penanganan retry di level aplikasi |
| Optimasi Indeks (Indexing) | Menengah | Positif (Meningkatkan kecepatan) | Mengurangi durasi lock dan mencegah table scan |
| Konsistensi Urutan Akses (Lock Ordering) | Tinggi | Sangat Baik | Transaksi kompleks yang mengakses banyak tabel sekaligus |
| Penurunan Level Isolasi (Isolation Level) | Menengah | Potensi Isu Konkurensi | Query baca-berat yang tidak membutuhkan serializability ketat |
Langkah Teknis Mengatasi dan Mencegah Deadlock
1. Identifikasi Log Deadlock melalui Sistem
Gunakan fungsi bawaan database untuk melihat riwayat deadlock terakhir. Pada MySQL InnoDB, gunakan perintah:
SHOW ENGINE INNODB STATUS;
Periksa bagian LATEST DETECTED DEADLOCK untuk mengetahui transaksi mana yang terlibat, tabel apa yang diakses, serta query SQL yang memicu konflik.
2. Perbaikan Urutan Akses Objek (Lock Ordering)
Penyebab utama deadlock adalah dua transaksi mengakses sekumpulan baris atau tabel dalam urutan yang berbeda. Pastikan seluruh aplikasi mengakses tabel dan kunci dalam urutan yang konsisten (misalnya selalu mengurutkan berdasarkan ID terkecil ke terbesar).
3. Optimasi Indeks untuk Mencegah Lock Eskalasi
Jika query melakukan pemindaian seluruh tabel (full table scan), database akan mengunci lebih banyak baris dari yang diperlukan, meningkatkan peluang terjadinya deadlock. Buat indeks pada kolom yang sering digunakan dalam klausa WHERE dan JOIN.
CREATE INDEX idx_user_status ON transactions (user_id, status);
4. Implementasikan Mekanisme Retry di Aplikasi
Karena deadlock terkadang tidak dapat dihindari pada sistem dengan konkurensi tinggi, pastikan kode aplikasi Anda menangkap exception deadlock (misalnya Error Code 1213 pada MySQL atau 40001 pada PostgreSQL) dan melakukan percobaan ulang (retry) transaksi secara otomatis.
import time
import pymysql
def execute_with_retry(connection, query, params, max_retries=3):
retries = 0
while retries < max_retries:
try:
with connection.cursor() as cursor:
cursor.execute(query, params)
connection.commit()
return
break
except pymysql.err.OperationalError as e:
if e.args[0] == 1213: # Deadlock error code
retries += 1
connection.rollback()
time.sleep(2 ** retries)
else:
raise e
raise Exception("Transaction failed due to persistent deadlock")
5. Gunakan Level Isolasi yang Tepat
Pertimbangkan penggunaan Read Committed daripada Repeatable Read jika aplikasi Anda dapat menoleransi fenomena non-repeatable reads, karena hal ini secara signifikan mengurangi jumlah shared lock yang bertahan selama transaksi.