Transactions
Transaction commands for grouping multiple operations into atomic units with optimistic locking support.
Commands
Section titled âCommandsâ| Command | Syntax | Description |
|---|---|---|
| MULTI | MULTI | Start a transaction block |
| EXEC | EXEC | Execute all queued commands atomically |
| DISCARD | DISCARD | Abort transaction and discard queued commands |
| WATCH | WATCH key [key ...] | Watch keys for changes (optimistic locking) |
| UNWATCH | UNWATCH | Clear all watched keys |
How Transactions Work
Section titled âHow Transactions WorkâMULTIstarts a transaction - commands are queued, not executed- Each command returns
QUEUEDinstead of its result EXECexecutes all queued commands atomically and returns resultsDISCARDaborts and clears the queue
Examples
Section titled âExamplesâBasic Transaction
Section titled âBasic Transactionâ127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET user:1:name "Alice"QUEUED127.0.0.1:6379> SET user:1:email "alice@example.com"QUEUED127.0.0.1:6379> INCR user:countQUEUED127.0.0.1:6379> EXEC1) OK2) OK3) (integer) 1Abort Transaction
Section titled âAbort Transactionâ127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET key1 "value1"QUEUED127.0.0.1:6379> SET key2 "value2"QUEUED127.0.0.1:6379> DISCARDOK
# Nothing was set - transaction aborted127.0.0.1:6379> GET key1(nil)Optimistic Locking with WATCH
Section titled âOptimistic Locking with WATCHâWATCH enables optimistic locking - the transaction aborts if any watched key changes before EXEC:
# Terminal 1: Watch and modify127.0.0.1:6379> SET balance 100OK127.0.0.1:6379> WATCH balanceOK127.0.0.1:6379> GET balance"100"127.0.0.1:6379> MULTIOK127.0.0.1:6379> DECRBY balance 50QUEUED
# Before EXEC, Terminal 2 modifies balance...
127.0.0.1:6379> EXEC(nil) # Transaction aborted - balance was modified!# Terminal 2: Concurrent modification127.0.0.1:6379> SET balance 200OKCheck-and-Set Pattern
Section titled âCheck-and-Set Patternâ# Increment only if value is what we expect127.0.0.1:6379> SET counter 10OK127.0.0.1:6379> WATCH counterOK127.0.0.1:6379> GET counter"10"
# Only proceed if counter is still 10127.0.0.1:6379> MULTIOK127.0.0.1:6379> SET counter 11QUEUED127.0.0.1:6379> EXEC1) OK # Success - counter wasn't modifiedClear Watches
Section titled âClear Watchesâ127.0.0.1:6379> WATCH key1 key2 key3OK127.0.0.1:6379> UNWATCHOK# All watches clearedTransfer Between Accounts
Section titled âTransfer Between Accountsâ127.0.0.1:6379> SET account:A 1000OK127.0.0.1:6379> SET account:B 500OK
# Atomic transfer of 200 from A to B127.0.0.1:6379> WATCH account:A account:BOK127.0.0.1:6379> MULTIOK127.0.0.1:6379> DECRBY account:A 200QUEUED127.0.0.1:6379> INCRBY account:B 200QUEUED127.0.0.1:6379> EXEC1) (integer) 8002) (integer) 700Library Mode (Rust)
Section titled âLibrary Mode (Rust)âFor embedded library mode, Redlite provides SQLite-level transactions which offer even stronger guarantees:
use redlite::Db;
let db = Db::open("mydata.db")?;
// SQLite transaction - all-or-nothingdb.with_transaction(|tx| { tx.set("user:1:name", b"Alice")?; tx.set("user:1:email", b"alice@example.com")?; tx.incr("user:count")?; Ok(())})?;
// Transaction with rollback on errordb.with_transaction(|tx| { tx.decrby("account:A", 200)?;
// Check balance let balance = tx.get("account:A")?.unwrap_or_default(); let balance: i64 = String::from_utf8_lossy(&balance).parse().unwrap_or(0);
if balance < 0 { return Err(redlite::error::KvError::Custom("Insufficient funds".into())); // Transaction automatically rolls back }
tx.incrby("account:B", 200)?; Ok(())})?;Important Notes
Section titled âImportant NotesâWATCH Behavior
Section titled âWATCH Behaviorâ- WATCH must be called before MULTI
- Watches persist until EXEC, DISCARD, or UNWATCH
- If any watched key is modified by another client, EXEC returns
nil - EXEC clears all watches automatically
Server Mode Only
Section titled âServer Mode Onlyâ- MULTI/EXEC/DISCARD/WATCH/UNWATCH are only available in server mode
- For embedded library mode, use
db.with_transaction()for SQLite transactions
Transaction Scope
Section titled âTransaction Scopeâ- Commands in a transaction see the database state at EXEC time
- No reads inside a transaction see uncommitted writes from the same transaction
- Use WATCH for read-modify-write patterns
Use Cases
Section titled âUse CasesâAtomic Counter with Limit
Section titled âAtomic Counter with LimitâWATCH counterGET counter# Check if counter < 100 in applicationMULTIINCR counterEXECInventory Management
Section titled âInventory ManagementâWATCH inventory:widgetGET inventory:widget# Check if inventory >= order_quantityMULTIDECRBY inventory:widget 5LPUSH orders:pending order:123EXECSession Management
Section titled âSession ManagementâMULTISET session:abc123 '{"user":"alice"}'EXPIRE session:abc123 3600SADD active_sessions "abc123"EXEC