Episode ini membahas cara Redis menjalankan beberapa perintah secara atomik dan sekuensial dengan MULTI/EXEC, melindungi data dari race condition menggunakan optimistic locking WATCH, serta teknik pipelining untuk memangkas network round-trip.

Sejauh ini kalian menjalankan perintah satu per satu. Tapi bagaimana jika beberapa perintah harus berjalan sebagai satu kesatuan — misalnya memindahkan saldo dari akun A ke akun B, atau mengurangi stok lalu mencatat pesanan? Episode 9 ini menjawabnya dengan Transactions (MULTI/EXEC), ditambah optimistic locking dengan WATCH dan teknik pipelining.
Penting untuk dipahami: transaksi Redis berbeda dari database SQL. Tidak ada rollback, tidak ada isolation tingkat tinggi — yang ada adalah atomicity dan sequential execution. Mari kita bedah maknanya.
MULTI memulai transaksi: perintah setelahnya tidak langsung dieksekusi, melainkan diantrekan. EXEC menjalankan seluruh antrean secara berurutan tanpa ada perintah lain yang menyela. Ini menjamin atomicity — semua perintah jalan, atau (jika ada error sintaks) tidak ada yang jalan.
redis-cli MULTI
redis-cli DECRBY account:A 100
redis-cli INCRBY account:B 100
redis-cli EXECMULTI memulai, DECRBY dan INCRBY diantrekan, lalu EXEC menjalankan keduanya tanpa diselingi client lain. Antara EXEC dan EXEC, Redis mengembalikan QUEUED untuk tiap perintah.
Jika berubah pikiran sebelum EXEC, gunakan DISCARD untuk membuang seluruh antrean:
redis-cli MULTI
redis-cli SET balance:1 0
redis-cli DISCARDredis-cli DISCARD membatalkan semua perintah yang sudah diantrekan tanpa mengeksekusi apa pun. Penting: transaksi Redis tidak punya rollback. Jika satu perintah gagal saat EXEC (misal type mismatch), perintah lain tetap dijalankan — tidak seperti database SQL yang memutar balik semuanya.
Info
Kekuatan MULTI/EXEC bukan rollback, melainkan eksekusi terkunci: tidak ada client lain yang bisa menyelip di antara perintah-perintah dalam satu transaksi. Untuk kebutuhan conditional logic, episode 10 akan memperkenalkan Lua yang jauh lebih kuat.
Transaksi saja belum cukup untuk skenario "baca lalu tulis". Contoh klasik: dua client membaca stok 5, keduanya mengurangi jadi 4, lalu menulis 4 — padahal stok seharusnya 3. Ini disebut race condition atau double spending.
WATCH menyelesaikan ini dengan optimistic locking: kalian memantau satu atau lebih key. Jika key tersebut berubah oleh client lain sebelum EXEC, transaksi dibatalkan dan EXEC mengembalikan nil — aplikasi harus mengulang dari awal.
redis-cli WATCH stock:sku-1
redis-cli GET stock:sku-1
redis-cli MULTI
redis-cli DECRBY stock:sku-1 1
redis-cli EXECWATCH stock:sku-1 mengunci pemantauan. Setelah GET, kalian melakukan MULTI...EXEC. Jika tidak ada client lain mengubah stock:sku-1 di antara WATCH dan EXEC, transaksi berhasil. Jika ada, EXEC mengembalikan nil dan aplikasi harus mengulang — inilah pola retry loop.
| Pendekatan | Cara Kerja | Risiko |
|---|---|---|
| Pessimistic lock | Kunci resource sebelum akses | Deadlock, overhead |
| Optimistic (WATCH) | Deteksi konflik saat commit | Retry yang harus di-handle aplikasi |
WATCH cocok untuk workload dengan sedikit konflik: transaksi jarang batal, jadi retry jarang terjadi. Ini pola dasar untuk stok produk, saldo akun, dan slot booking di aplikasi berskala besar.
Setiap perintah Redis memakan satu network round-trip. Jika kalian mengirim 100 perintah, ada 100 kali bolak-balik jaringan. Pipelining mengirim semua perintah dalam satu batch tanpa menunggu respons satu per satu, lalu membaca semua respons sekaligus:
printf 'SET k1 v1\r\nSET k2 v2\r\nGET k1\r\nGET k2\r\n' | redis-cli --piperedis-cli --pipe membaca banyak perintah sekaligus dan mengirimnya dalam satu sesi — menghemat overhead jaringan secara dramatis. Ini berguna untuk seed data atau batch operation. Di aplikasi, library seperti ioredis atau redis-py menyediakan pipeline() untuk tujuan yang sama.
Success
Bedakan dengan MULTI/EXEC: pipelining hanya menggabungkan jaringan, tidak menjamin atomicity. Untuk batch yang harus atomik, kombinasikan keduanya — pipeline yang membungkus MULTI/EXEC.
Pipelining bukan ajaib: respons harus tetap diproses dalam urutan yang sama. Untuk batch raksasa, pecah menjadi chunk agar memori client tidak jebol.
Tiga mekanisme ini sering tertukar. Ini pembeda tegasnya:
| Mekanisme | Eksekusi atomik | Menghemat jaringan | Logika conditional |
|---|---|---|---|
MULTI/EXEC | Ya | Tidak | Tidak |
| Pipelining | Tidak | Ya | Tidak |
| Lua script | Ya | Ya | Ya |
Pilih sesuai kebutuhan: butuh atomicity sederhana → MULTI/EXEC; butuh kirim banyak perintah → pipelining; butuh keputusan di dalam batch → Lua (episode 10).
KEYS *) di dalam transaksi — blokirnya jadi lebih lama.MULTI untuk mencegah race condition — itu tugas WATCH, bukan MULTI.EXEC mengembalikan nil karena WATCH.Episode 9 membekali kalian transaksi Redis dan teknik pengoptimasinya: MULTI/EXEC untuk eksekusi atomik sekuensial, DISCARD untuk pembatalan, WATCH untuk optimistic locking melawan race condition, dan pipelining untuk memangkas network round-trip.
Inti yang harus dibawa pulang:
MULTI mengantre perintah, EXEC menjalankannya tanpa interupsi client lain.WATCH membatalkan transaksi jika key yang dipantau berubah sebelum EXEC.Di episode 10 selanjutnya kita membahas Lua Scripting & Redis Functions — menjalankan logika kompleks di server Redis secara atomik. Kalian akan belajar EVAL/EVALSHA, menulis script Lua dengan conditional logic, serta mendaftarkan function permanen dengan Redis Functions di Redis 7. Siap?