Pelajari bagaimana jaminan ACID memengaruhi desain basis data dan perilaku aplikasi. Jelajahi atomisitas, konsistensi, isolasi, durabilitas, trade-off, dan contoh nyata.

Saat Anda membayar bahan makanan, memesan tiket, atau memindahkan uang antar rekening, Anda mengharapkan hasil yang tegas: berhasil atau gagal. Basis data berusaha memberikan kepastian yang sama—bahkan saat banyak orang menggunakan sistem bersamaan, server jatuh, atau jaringan bermasalah.
Sebuah transaksi adalah satu unit kerja yang diperlakukan basis data sebagai satu "paket." Ia mungkin melibatkan beberapa langkah—mengurangi inventaris, membuat catatan order, membebankan kartu, dan menulis tanda terima—tetapi dimaksudkan berperilaku sebagai satu tindakan koheren.
Jika ada langkah yang gagal, sistem sebaiknya memutar kembali ke titik aman daripada meninggalkan keadaan setengah jadi.
Pembaharuan parsial bukan sekadar gangguan teknis; mereka menjadi tiket dukungan pelanggan dan risiko finansial. Misalnya:
Kegagalan ini sulit di-debug karena semuanya terlihat “hampir benar,” tetapi angkanya tidak cocok.
ACID adalah singkatan untuk empat jaminan yang banyak basis data sediakan untuk transaksi:
Bukan merek basis data atau satu fitur yang Anda aktifkan; ini janji tentang perilaku.
Jaminan yang lebih kuat biasanya berarti basis data harus melakukan lebih banyak kerja: koordinasi ekstra, menunggu kunci, melacak versi, dan menulis ke log. Itu dapat mengurangi throughput atau menambah latensi saat beban tinggi. Tujuannya bukan “ACID maksimal setiap saat,” melainkan memilih jaminan yang sesuai dengan risiko bisnis nyata Anda.
Atomicity berarti sebuah transaksi diperlakukan sebagai satu unit kerja: ia selesai sepenuhnya atau tidak berpengaruh sama sekali. Anda tidak pernah mendapatkan “setengah pembaruan” yang terlihat di basis data.
Bayangkan mentransfer $50 dari Alice ke Bob. Di balik layar, ini biasanya melibatkan sedikitnya dua perubahan:
Dengan atomicity, kedua perubahan itu berhasil bersama atau gagal bersama. Jika sistem tidak bisa dengan aman melakukan keduanya, maka tidak boleh dilakukan keduanya. Itu mencegah hasil buruk di mana Alice dikenai biaya tetapi Bob tidak menerima uang (atau Bob menerima tanpa Alice terdebit).
Basis data memberi transaksi dua jalan keluar:
Model mental yang berguna adalah “draft vs. publish.” Ketika transaksi berjalan, perubahan bersifat sementara. Hanya commit yang mem-publish perubahan.
Atomicity penting karena kegagalan itu normal:
Jika ini terjadi sebelum commit selesai, atomicity memastikan basis data bisa rollback sehingga pekerjaan parsial tidak bocor ke saldo nyata.
Atomicity melindungi state basis data, tetapi aplikasi Anda tetap harus menangani ketidakpastian—terutama saat putus jaringan membuat tidak jelas apakah commit terjadi.
Dua pelengkap praktis:
Bersama-sama, transaksi atomik dan retry idempoten membantu Anda menghindari pembaruan parsial dan penagihan ganda yang tidak disengaja.
Consistency dalam ACID bukan berarti “data terlihat masuk akal” atau “semua replika cocok.” Ini berarti setiap transaksi harus membawa basis data dari satu state valid ke state valid berikutnya—menurut aturan yang Anda definisikan.
Basis data hanya bisa menjaga konsistensi relatif terhadap konstraint eksplisit, trigger, dan invariant yang menjelaskan apa arti "valid" untuk sistem Anda. ACID tidak menciptakan aturan ini; ia menegakkannya selama transaksi.
Contoh umum meliputi:
order.customer_id harus menunjuk ke pelanggan yang ada.Jika aturan-aturan ini ada, basis data akan menolak transaksi yang melanggarnya—sehingga Anda tidak berakhir dengan data yang “setengah valid.”
Validasi di aplikasi penting, tetapi tidak cukup sendirian.
Mode kegagalan klasik adalah memeriksa sesuatu di app ("email tersedia") lalu menyisipkan baris. Di bawah konkurensi, dua permintaan bisa lewat pengecekan pada saat bersamaan. Unique constraint di basis datalah yang menjamin hanya satu insert berhasil.
Jika Anda mengkodekan "saldo tidak negatif" sebagai konstraint (atau menegakkannya dengan benar dalam satu transaksi), maka setiap transfer yang membuat rekening tertarik harus gagal secara keseluruhan. Jika Anda tidak mendefinisikan aturan itu di mana pun, ACID tidak bisa melindunginya—karena tidak ada yang menegakkannya.
Consistency pada akhirnya soal eksplisit: definisikan aturan, lalu biarkan transaksi memastikan aturan itu tidak pernah dilanggar.
Isolation memastikan transaksi tidak saling menginjak. Saat sebuah transaksi berjalan, transaksi lain tidak boleh melihat kerja yang setengah jadi atau secara tidak sengaja menimpanya. Tujuannya sederhana: setiap transaksi harus berperilaku seolah-olah ia berjalan sendirian, meskipun banyak pengguna aktif bersamaan.
Sistem nyata sibuk: pelanggan memesan, agen dukungan memperbarui profil, job latar belakang merekonsiliasi pembayaran—semua terjadi bersamaan. Aksi-aksi ini tumpang tindih dalam waktu, dan sering menyentuh baris yang sama (saldo akun, hitungan inventaris, atau slot pemesanan).
Tanpa isolasi, timing menjadi bagian dari logika bisnis Anda. Pembaruan “kurangi stok” bisa balapan dengan checkout lain, atau laporan bisa membaca data di tengah perubahan dan menampilkan angka yang tidak pernah ada dalam keadaan stabil.
Isolasi penuh "bertindak seolah-olah Anda sendirian" bisa mahal. Itu dapat mengurangi throughput, menambah waktu tunggu (kunci), atau menyebabkan retry transaksi. Sementara itu, banyak alur kerja tidak membutuhkan perlindungan terketat—membaca analitik kemarin, misalnya, bisa mentolerir sedikit inkonsistensi.
Itulah mengapa basis data menawarkan level isolasi yang dapat Anda pilih: seberapa banyak risiko konkurensi yang Anda terima sebagai tukar performa dan lebih sedikit konflik.
Saat isolasi terlalu lemah untuk beban kerja Anda, Anda akan menemui anomali klasik:
Memahami mode kegagalan ini memudahkan memilih level isolasi yang sesuai dengan janji produk Anda.
Isolasi menentukan apa yang transaksi lain boleh “lihat” saat transaksi Anda masih berjalan. Saat isolasi terlalu lemah, Anda bisa mendapatkan anomali—perilaku yang mungkin terjadi secara teknis tetapi mengejutkan pengguna.
Dirty read terjadi saat Anda membaca data yang ditulis transaksi lain tetapi belum dikomit.
Skenario: Alex mentransfer $500 keluar dari sebuah akun, saldo sementara menjadi $200, dan Anda membaca $200 itu sebelum transfer Alex kemudian gagal dan di-rollback.
Dampak pengguna: pelanggan melihat saldo rendah yang salah, aturan fraud memicu secara keliru, atau agen dukungan memberikan jawaban yang salah.
Non-repeatable read berarti Anda membaca baris yang sama dua kali dan mendapatkan nilai berbeda karena transaksi lain mengkomit di antaranya.
Skenario: Anda memuat total order ($49.00), lalu menyegarkan sebentar kemudian melihat $54.00 karena baris diskon dihapus.
Dampak pengguna: "Total saya berubah saat saya cek out," menyebabkan ketidakpercayaan atau keranjang ditinggalkan.
Phantom read mirip non-repeatable read, tetapi pada himpunan baris: query kedua mengembalikan baris tambahan (atau hilang) karena transaksi lain menyisipkan/menghapus record yang cocok.
Skenario: Pencarian hotel menunjukkan "3 kamar tersedia," lalu saat memesan sistem memeriksa kembali dan menemukan tak ada karena reservasi baru ditambahkan.
Dampak pengguna: percobaan double booking, layar ketersediaan tidak konsisten, atau overselling inventaris.
Lost update terjadi ketika dua transaksi membaca nilai yang sama dan keduanya menulis kembali pembaruan, dengan tulis terakhir menimpa yang sebelumnya.
Skenario: Dua admin mengedit harga produk yang sama. Keduanya mulai dari $10; satu menyimpan $12, yang lain menyimpan $11 terakhir.
Dampak pengguna: perubahan seseorang hilang; total dan laporan salah.
Write skew terjadi ketika dua transaksi masing-masing membuat perubahan yang secara individu valid, tetapi bersama-sama melanggar aturan.
Skenario: Aturan: “Setidaknya satu dokter on-call harus terjadwal.” Dua dokter secara independen menandai diri off-call setelah memeriksa bahwa yang lain masih on-call.
Dampak pengguna: Anda berakhir tanpa cakupan, meskipun setiap transaksi “lulus” pengecekannya.
Isolasi lebih kuat mengurangi anomali tetapi dapat menambah waktu tunggu, retry, dan biaya saat konkurensi tinggi. Banyak sistem memilih isolasi lebih lemah untuk analitik baca-berat, sementara menggunakan pengaturan lebih ketat untuk pergerakan uang, pemesanan, dan alur lain yang kritis terhadap kebenaran.
Isolasi tentang apa yang transaksi Anda boleh “lihat” sementara transaksi lain berjalan. Basis data mengekspresikan ini sebagai level isolasi: level lebih tinggi mengurangi perilaku mengejutkan, tetapi bisa menambah biaya throughput atau waktu tunggu.
Tim sering memilih Read Committed sebagai default untuk aplikasi user-facing: performa baik, dan "tanpa dirty reads" cocok dengan ekspektasi kebanyakan orang.
Gunakan Repeatable Read saat Anda butuh hasil stabil di dalam transaksi (mis. membuat faktur dari sekumpulan line item) dan bisa mentolerir overhead. Gunakan Serializable saat kebenaran lebih penting daripada konkurensi (mis. menegakkan invariant kompleks seperti "tidak pernah oversell"), atau saat Anda tidak mudah memikirkan race condition di kode aplikasi.
Read Uncommitted jarang dipakai di sistem OLTP; kadang digunakan untuk monitoring atau pelaporan perkiraan di mana bacaan salah sesekali dapat diterima.
Nama-nama distandarisasi, tetapi jaminan tepat berbeda menurut engine basis data (dan kadang menurut konfigurasi). Konfirmasikan dengan dokumentasi basis data Anda dan uji anomali yang penting bagi bisnis Anda.
Durability berarti setelah sebuah transaksi dikomit, hasilnya harus bertahan dari crash—kehilangan daya, restart proses, atau reboot mesin mendadak. Jika aplikasi Anda memberi tahu pelanggan "pembayaran berhasil", durability adalah janji bahwa basis data tidak akan "melupakan" fakta itu setelah kegagalan berikutnya.
Kebanyakan basis data relasional mencapai durability dengan write-ahead logging (WAL). Secara garis besar, basis data menulis "tanda terima" berurutan dari perubahan ke log di disk sebelum menganggap transaksi dikomit. Jika basis data crash, ia bisa memutar ulang log saat startup untuk memulihkan perubahan yang sudah dikomit.
Untuk menjaga waktu pemulihan tetap wajar, basis data juga membuat checkpoint. Checkpoint adalah momen di mana basis data memastikan cukup perubahan terbaru telah ditulis ke file data utama, sehingga pemulihan tidak perlu memutar ulang sejarah log yang tak terbatas.
Durability bukan saklar on/off; ia bergantung pada seberapa agresif basis data memaksa data ke penyimpanan yang stabil.
fsync level OS) sebelum mengonfirmasi commit. Ini lebih aman, tapi dapat menambah latensi.Perangkat keras di bawahnya juga penting: SSD, RAID controller dengan write cache, dan volume cloud bisa berperilaku berbeda saat kegagalan.
Backup dan replikasi membantu Anda memulihkan atau mengurangi downtime, tapi bukan hal yang sama dengan durability. Sebuah transaksi bisa durable di primary meskipun belum mencapai replica, dan backup biasanya snapshot titik-waktu bukannya jaminan per-commit.
Saat Anda BEGIN sebuah transaksi dan kemudian COMMIT, basis data mengoordinasikan banyak bagian: siapa boleh membaca baris mana, siapa boleh memperbarui, dan apa yang terjadi jika dua orang mencoba mengubah record yang sama.
Pilihan penting “di balik layar” adalah bagaimana menangani konflik:
Banyak sistem memadukan kedua ide tergantung beban kerja dan level isolasi.
Basis data modern sering menggunakan MVCC (Multi-Version Concurrency Control): alih-alih hanya menyimpan satu salinan baris, basis data menyimpan beberapa versi.
Ini alasan besar beberapa basis data menangani banyak baca dan tulis secara bersamaan dengan lebih sedikit blocking—meskipun konflik tulis/tulis tetap perlu diselesaikan.
Kunci bisa menyebabkan deadlock: Transaksi A menunggu kunci yang dipegang B, sementara B menunggu kunci yang dipegang A.
Basis data biasanya menyelesaikan ini dengan mendeteksi siklus dan membatalkan salah satu transaksi ("deadlock victim"), mengembalikan error sehingga aplikasi dapat retry.
Jika penegakan ACID menyebabkan friction, Anda sering melihat:
Gejala ini sering berarti saatnya meninjau ukuran transaksi, indexing, atau strategi isolasi/penguncian yang sesuai untuk beban kerja.
Jaminan ACID bukan hanya teori basis data—mereka memengaruhi bagaimana Anda mendesain API, job latar belakang, dan bahkan alur UI. Ide inti: putuskan langkah mana yang harus berhasil bersama, lalu bungkus hanya langkah-langkah itu dalam transaksi.
API transaksional yang baik biasanya memetakan ke satu tindakan bisnis, meskipun menyentuh banyak tabel. Misalnya, operasi /checkout bisa: membuat order, mereservasi inventaris, dan mencatat payment intent. Tulis basis data itu biasanya sebaiknya berada dalam satu transaksi sehingga commit bersama (atau rollback bersama) jika ada validasi yang gagal.
Pola umum:
Ini menjaga atomicity dan consistency sambil menghindari transaksi yang lambat dan rapuh.
Di mana Anda menempatkan batas transaksi tergantung pada apa arti "satu unit kerja":
ACID membantu, tapi aplikasi Anda tetap harus menangani kegagalan dengan benar:
Hindari transaksi panjang, memanggil API eksternal di dalam transaksi, dan waktu pikir pengguna di dalam transaksi (mis. "kunci baris keranjang, minta pengguna konfirmasi"). Ini menambah kontensi dan membuat konflik isolasi jauh lebih mungkin.
Jika Anda membangun sistem transaksional dengan cepat, risiko terbesar jarang "tidak tahu ACID"—melainkan menyebarkan satu tindakan bisnis ke banyak endpoint, job, atau tabel tanpa batas transaksi yang jelas.
Platform seperti Koder.ai bisa membantu mempercepat sambil tetap merancang di sekitar ACID: Anda bisa mendeskripsikan alur kerja (mis. "checkout dengan reservasi inventaris dan payment intent") di chat perencanaan, menghasilkan UI React plus backend Go + PostgreSQL, dan iterasi dengan snapshot/rollback jika skema atau batas transaksi perlu diubah. Basis data tetap menegakkan jaminan; nilai tambahnya mempercepat jalan dari desain benar ke implementasi bekerja.
Satu basis data biasanya bisa memberikan jaminan ACID dalam satu batas transaksi. Setelah Anda menyebarkan kerja ke banyak layanan (dan seringkali banyak basis data), jaminan yang sama menjadi lebih sulit dipertahankan—dan lebih mahal bila dicoba.
Konsistensi ketat berarti setiap baca melihat "kebenaran commit terbaru." Ketersediaan tinggi berarti sistem terus merespons meskipun beberapa bagian lambat atau tidak dapat dijangkau.
Dalam setup multi-layanan, masalah jaringan sementara dapat memaksa pilihan: blokir atau gagal request sampai setiap peserta setuju (lebih konsisten, kurang tersedia), atau terima bahwa layanan mungkin sementara tidak sinkron (lebih tersedia, kurang konsisten). Tidak ada yang selalu benar—tergantung kesalahan apa yang bisnis Anda bisa toleransi.
Transaksi terdistribusi membutuhkan koordinasi melintasi batas yang tidak sepenuhnya Anda kendalikan: delay jaringan, retry, timeout, crash layanan, dan kegagalan parsial.
Bahkan jika setiap layanan benar, jaringan bisa menciptakan ambiguitas: apakah layanan pembayaran mengkomit tetapi layanan order tidak menerima ack? Untuk menyelesaikannya dengan aman, sistem menggunakan protokol koordinasi (seperti two-phase commit), yang bisa lambat, mengurangi availability saat kegagalan, dan menambah kompleksitas operasional.
Sagas memecah alur kerja menjadi langkah-langkah, masing-masing dikomit secara lokal. Jika langkah selanjutnya gagal, langkah-langkah sebelumnya "dibatalkan" menggunakan aksi kompensasi (mis. refund).
Outbox/inbox membuat publishing event dan konsumsi dapat diandalkan. Sebuah layanan menulis data bisnis dan sebuah record "event untuk dipublikasikan" dalam satu transaksi lokal (outbox). Konsumen mencatat ID pesan yang sudah diproses (inbox) untuk menangani retry tanpa menduplikasi efek.
Eventual consistency menerima jendela pendek di mana data berbeda antar layanan, dengan rencana rekonsiliasi yang jelas.
Relaksasi jaminan saat:
Kendalikan risiko dengan mendefinisikan invariant (apa yang tidak boleh dilanggar), merancang operasi idempoten, menggunakan timeout dan retry dengan backoff, serta memonitor drift (saga yang macet, kompensasi berulang, tabel outbox yang membesar). Untuk invariant yang benar-benar kritis (mis. "tidak pernah membelanjakan akun lebih dari saldonya"), pertahankan mereka di dalam satu layanan dan satu transaksi basis data bila memungkinkan.
Sebuah transaksi bisa "benar" di unit test namun gagal di bawah lalu lintas nyata, restart, dan konkurensi. Gunakan daftar periksa ini agar jaminan ACID selaras dengan perilaku produksi.
Mulailah dengan menuliskan apa yang harus selalu benar (invariant data Anda). Contoh: "saldo akun tidak pernah negatif," "total order sama dengan jumlah line item," "inventaris tidak boleh turun di bawah nol," "sebuah pembayaran terhubung ke tepat satu order." Perlakukan ini sebagai aturan produk, bukan trivia basis data.
Kemudian putuskan apa yang harus berada dalam satu transaksi versus apa yang bisa ditunda.
Jaga transaksi kecil: sentuh lebih sedikit baris, lakukan pekerjaan lebih sedikit (jangan panggil API eksternal), dan commit cepat.
Jadikan konkurensi sebagai dimensi uji.
Jika Anda mendukung retry, tambahkan idempotency key eksplisit dan uji "permintaan diulang setelah sukses."
Pantau indikator bahwa jaminan Anda menjadi mahal atau rapuh:
Beri alert pada tren, bukan hanya lonjakan, dan kaitkan metrik ke endpoint atau job yang menyebabkannya.
Gunakan isolasi terlemah yang masih melindungi invariant Anda; jangan langsung "maksimalkan". Saat Anda butuh ketepatan untuk bagian kecil yang kritis (pergerakan uang, pengurangan inventaris), persempit transaksi hanya ke bagian itu dan taruh semua lainnya di luar.
ACID adalah seperangkat jaminan transaksional yang membantu basis data berperilaku terduga saat terjadi kegagalan dan kondisi konkurensi:
Transaksi adalah satu “unit kerja” yang dianggap sebagai satu paket oleh basis data. Meskipun melakukan beberapa pernyataan SQL (mis. membuat order, mengurangi inventaris, mencatat intent pembayaran), transaksi hanya punya dua hasil:
Karena partial update menciptakan kontradiksi dunia nyata yang mahal untuk diperbaiki nanti—misalnya:
ACID (khususnya atomicity + consistency) mencegah keadaan “setengah jadi” ini muncul sebagai kebenaran.
Atomicity memastikan basis data tidak pernah memaparkan transaksi yang “setengah jadi”. Jika sesuatu gagal sebelum commit—crash aplikasi, putus jaringan, restart DB—transaksi akan di-rollback sehingga langkah awal tidak bocor ke state persisten.
Secara praktis, atomicity membuat perubahan multi-langkah (mis. transfer yang memperbarui dua saldo) menjadi aman.
Anda tidak selalu dapat mengetahui apakah commit terjadi jika klien kehilangan respons (mis. timeout jaringan tepat setelah commit). Gabungkan transaksi ACID dengan:
Ini mencegah partial update dan double-charge/double-write yang tidak disengaja.
Dalam ACID, “consistency” berarti basis data berpindah dari satu keadaan valid ke keadaan lain menurut aturan yang Anda tentukan—konstraint, foreign key, unique, dan check.
Jika Anda tidak mendefinisikan aturan (mis. “saldo tidak boleh negatif”), ACID tidak bisa menegakkannya secara otomatis. Basis data membutuhkan invariants eksplisit agar bisa melindungi.
Validasi di aplikasi meningkatkan pengalaman pengguna dan dapat menegakkan aturan rumit, tetapi dapat gagal di bawah konkurensi (dua permintaan lulus pengecekan bersamaan).
Konstraint basis data adalah penjaga terakhir:
Gunakan keduanya: validasi di awal di aplikasi, dan penegakan pasti di basis data.
Isolation mengontrol apa yang transaksi Anda boleh lihat saat transaksi lain berjalan. Isolasi lemah dapat menghasilkan anomali seperti:
Level isolasi memungkinkan Anda menukar performa dengan perlindungan terhadap anomali ini.
Praktik umum yang masuk akal adalah Read Committed untuk banyak aplikasi OLTP karena mencegah dirty reads dengan performa baik. Naikkan jika perlu:
Selalu konfirmasi perilaku pada engine basis data Anda karena detailnya berbeda-beda.
Durability berarti setelah basis data mengonfirmasi commit, perubahan akan bertahan dari crash. Biasanya diimplementasikan lewat write-ahead logging (WAL) dan checkpoint.
Perlu diingat trade-off konfigurasi:
Backup dan replikasi membantu recovery/availability, tetapi bukan jaminan durability per commit.