Optimistic vs Pessimistic Locking: Mengatasi Rebutan Data di Database

Seribu orang ngeklik "Beli Sekarang" di detik yang sama buat rebutan 1 tiket terakhir. Kira-kira apa yang bakal terjadi di server kalian? Yuk, kita banding pessimistic sama optimistic locking!

Optimistic vs Pessimistic Locking: Mengatasi Rebutan Data di Database

Seribu orang ngeklik tombol "Beli Sekarang" di detik yang sama, cuma buat rebutan 1 tiket konser terakhir. Kira-kira, apa yang terjadi di server? 🤔

Tanpa mekanisme pengamanan concurrency yang bener, sistem kalian bisa kena bencana yang namanya Race Condition atau Lost Update Problem. Tiketnya kejual ke 5 orang sekaligus, sementara stok di database malah berubah minus. Kacau banget, kan? 😅

Di dunia backend dan database, dua transaksi yang nge-update row yang sama secara bersamaan harus diatur dengan cermat. Dua pendekatan yang paling sering dipakai buat nanganin rebutan data ini adalah Pessimistic Locking dan Optimistic Locking.

Yuk, kita bedah bedanya, plus kapan mending pakai yang mana.

Poin Penting

  • Race Condition dan Lost Update Problem muncul pas banyak pengguna ngedit row yang sama secara barengan.
  • Pessimistic Locking ngunci data secara fisik di level database lewat SELECT ... FOR UPDATE, cocok buat persaingan tinggi kayak flash sale tiket.
  • Optimistic Locking main di kolom version atau timestamp tanpa ngunci row, pas buat trafik high read dengan frekuensi konflik rendah.
  • Pemilihan strategi yang tepat ngejaga integritas data tanpa ngorbanin throughput aplikasi.

Gimana Cara Orang Ngedit Dokumen Bareng?

Biar kebayang, anggap aja dua transaksi itu kayak dua orang yang ngedit dokumen yang sama di kantor.

Gaya pertama itu pessimistic: seorang staf ngambil dokumen fisik dari lemari arsip, terus ngunci lemarinya pakai gembok dan bawa kuncinya. Siapa pun yang mau baca atau ngedit harus ngantre berdiri di depan lemari sampai staf itu kelar. Filosofinya kira-kira: "Ah, paling bakal ada yang ngubah barengan, mending dikunci dari awal aja, deh."

Gaya kedua itu optimistic: dokumennya difotokopi dan dibagi ke semua orang, tiap lembar dikasih nomor versi. Semua bebas ngedit di mejanya masing-masing. Pas mau nyimpen ke arsip pusat, barulah dicek—"masih versi 1.0 nggak? Kalau iya, simpan dan naikin jadi 1.1. Kalau udah ada yang nyimpen 1.1 lebih dulu, revisimu ditolak, ambil salinan terbaru!" Gaya ini santai di awal, tapi tegas di akhir.

Apa Sih Pessimistic Locking Itu?

Pessimistic Locking bekerja dengan ngunci row (row-level lock) atau tabel langsung di database. Fitur ini disediakan lewat transaksi relasional di database kayak PostgreSQL atau MySQL.

Pas transaksi dimulai, query-nya baca data pakai klausa SELECT ... FOR UPDATE:

SQL
BEGIN;

-- Mengunci baris produk ID 42 agar nggak bisa diubah transaksi lain
SELECT id, stock, price
FROM products
WHERE id = 42
FOR UPDATE;

-- Lakukan kalkulasi di aplikasi
-- Update stok jika masih tersedia
UPDATE products
SET stock = stock - 1
WHERE id = 42;

COMMIT; -- Gembok dilepas, transaksi lain baru boleh masuk

Kelebihannya jelas: aman. Kita dijamiin 100% nggak ada data yang tumpang tindih, soalnya transaksi lain dipaksa ngantre (blocking).

Tapi, ada harganya. Throughput bisa turun drastis kalau banyak request ngantre di row yang sama. Dan kalau kita kurang hati-hati ngatur urutan penguncian, sistem bisa kena Deadlock (kebuntuan) di mana dua transaksi saling nunggu selamanya.

Terus, Optimistic Locking Kerjanya Gimana?

Beda sama yang tadi, Optimistic Locking sebenernya nggak ngunci apa pun secara fisik. Pendekatan ini ngandelin logika aplikasi, dengan bantuan kolom penanda versi kayak version INT atau updated_at TIMESTAMP.

Alurnya kira-kira gini:

  1. Baca data beserta versinya sekarang.
    SQL
    SELECT id, stock, version FROM products WHERE id = 42;
    -- Hasil: stock = 10, version = 1
  2. Hitung di aplikasi, terus simpan cuma kalau versinya belum berubah.
    SQL
    UPDATE products
    SET stock = stock - 1, version = version + 1
    WHERE id = 42 AND version = 1;
  3. Cek jumlah row yang kena dampak (rows affected). Kalau hasilnya 1, berarti berhasil dan versinya naik jadi 2. Kalau hasilnya 0, artinya ada transaksi lain yang nyimpen lebih dulu—aplikasi bisa ngebatalin atau nyoba retry.

Kelebihannya, ini cepat dan nggak ada proses yang diblokir (non-blocking). Cocok banget buat aplikasi yang beban bacanya tinggi (high read throughput).

Kekurangannya, kalau tingkat bentrokan (contention) tinggi—misal rebutan 1 tiket konser—mayoritas transaksi bakal gagal. Retry beruntun itulah yang akhirnya ngabisin CPU kalian. 😅

Contoh Kode di Python / SQLAlchemy

Berikut perbandingannya pakai SQLAlchemy Concurrency:

PYTHON
from sqlalchemy.orm import Session
from sqlalchemy import select
from models import Product

# 1. Implementasi Pessimistic Locking
def buy_product_pessimistic(db: Session, product_id: int, quantity: int):
    # Menggunakan with_for_update() untuk memicu 'SELECT ... FOR UPDATE'
    product = db.execute(
        select(Product)
        .where(Product.id == product_id)
        .with_for_update()
    ).scalar_one()

    if product.stock < quantity:
        raise ValueError("Stok nggak mencukupi!")

    product.stock -= quantity
    db.commit()
    return product

# 2. Implementasi Optimistic Locking
def buy_product_optimistic(db: Session, product_id: int, quantity: int):
    # Baca data tanpa lock fisik
    product = db.execute(
        select(Product).where(Product.id == product_id)
    ).scalar_one()

    if product.stock < quantity:
        raise ValueError("Stok nggak mencukupi!")

    current_version = product.version

    # Update bersyarat mencocokkan nomor versi
    result = db.query(Product).filter(
        Product.id == product_id,
        Product.version == current_version
    ).update({
        "stock": product.stock - quantity,
        "version": current_version + 1
    })

    if result == 0:
        db.rollback()
        raise ValueError("Bentrokan data terdeteksi! Silakan ulangi transaksi.")

    db.commit()
    return product

Di versi optimistic, kunci utamanya ada di klausa WHERE id = 42 AND version = 1. Kalau versinya udah berubah duluan, update-nya nggak ngefek ke row mana pun, dan result bakal bernilai 0. Cek inilah yang jadi pengganti kunci fisik.

Kapan Pakai yang Mana, Sih?

Gampangnya, lihat seberapa sering bentrokan datanya terjadi.

Kriteria Pessimistic Locking Optimistic Locking
Tingkat Bentrokan Tinggi (banyak yang rebutan 1 row). Rendah sampai sedang.
Karakteristik Trafik Transaksi finansial, flash sale, booking. Profil user, edit blog, katalog umum.
Biaya Kegagalan Antrean waktu tunggu (blocking latency). Biaya komputasi buat retry.
Mekanisme Kunci fisik database (FOR UPDATE). Kolom version / timestamp di logika aplikasi.

Jadi, buat persaingan tinggi yang butuh integritas mutlak, pakai pessimistic. Buat trafik yang didominasi baca dengan konflik jarang, optimistic jauh lebih enteng.

Jadi, Mana yang Harus Kita Pilih?

Nggak ada solusi tunggal yang sempurna buat semua kasus. Yang penting, kita paham dulu karakter transaksi di aplikasi sendiri.

Pakai Pessimistic Locking pas integritas mutlak tanpa toleransi retry bener-bener dibutuhkan di tengah persaingan tinggi. Sebaliknya, manfaatkan Optimistic Locking biar sistem tetap gesit di transaksi yang risikonya bentrok rendah.

Kalau salah pilih, bukan cuma data yang kacau—CPU kalian juga bisa ikut nangis. Hehe.

Selamat ber-locking ria, dan semoga transaksi kalian selalu selamat dari rebutan yang bikin pusing! 👋

Inva

Writer

Biar makin jago ngoding.

Yuk gabung bareng temen-temen developer lainnya buat dapet update teknologi, tips, dan tutorial santai tiap minggu.

Biar Nggak Kudet

Update teknologi, tips ngoding, dan insight santai langsung ke email kamu tiap minggu.

Santai, anti spam. Bisa berhenti langganan kapan aja.

Baca Selanjutnya

Lihat semua
Kenapa Butuh Rate Limiting?
backendKenapa Butuh Rate Limiting?

Pernah nggak sih endpoint login kalian diserbu bot yang nyoba nembak ribuan password cuma dalam semenit? Yuk, kita bahas kenapa Rate Limiting itu wajib, plus cara masangnya di FastAPI!

© 2026 Inva.dev.