Redis implements a transaction mechanism enabling atomic execution of command groups, ensuring all commands succeed or none execute, thus maintaining data consistency. The following commands and methods are central to Redis transactions.
Initiating Transactions
MULTI
- Starts a transaction, marking its beginning.
Queueing Commands
command
- Commands issued between MULTI and EXEC are queued into a transaction list.
Committing Transactions
EXEC
- Executes all queued commands. If errors occur between MULTI and EXEC, no commands run, and results return as an array of each command's outcome.
Canceling Transactions
DISCARD
- Cancels the transaction, clears the command queue, and returns to non-transaction mode.
Key Monitoring for Optimistic Locking
WATCH key [key …]
- Monitors one or more keys. If another client modifies a watched key before EXEC, the transaction aborts, implementing optimistic locking.
Transaction Example
MULTI // Start transaction
SET user1 john // Queue command
SET user2 jane // Queue command
GET user1 // Queue command
EXEC // Execute transaction
Errors between MULTI and EXEC, such as syntax or runtime issues, prevent the entire transaction from executing, leaving the database unaffected.
Transaction Considerations
- Redis transactions are atomic but lack rollback capability.
- Changes to watched keys before EXEC abort the transaction, managed via WATCH for optimistic locking.
- Transactions do not support isolation levels like those in SQL databases.
Use Cases
- Batch write operations, e.g., setting multiple key-value pairs.
- Ensuring atomicity for grouped operations, such as debit and credit in transfers.
- Performance enhancement by reducing client-server round trips via command batching in a single transaction.
Redis transactions guarantee atomicity for command sequences, aiding in complex operations to ensure data integrity.
Key Insights on Transactions
Redis commands are atomic individually, but transactions are not atomic and lack isolation. A transaction is a serialized collection of commands executed sequentially and exclusively.
- Start transaction (multi)
- Queue commands (each command enters a QUEUED list without execution)
- Execute transaction (exec) (commands run in order from the queue)
If a command is incorrect during queueing (e.g., syntax error), it and valid commands still queue, but exec fails all commands (similar to compile-time errors in Java). If commands appear correct but contain logical errors (e.g., incrementing null or division by zero), exec executes valid commands and throws exceptions for errors, showing lack of atomicity (akin to runtime exceptions in Java).
DISCARD aborts a transaction before exec, discarding all queued commands.
Redis supports optimistic locking with WATCH. For instance, WATCH balance monitors a variable. If thread1 starts a transaction on balance and thread2 modifies it before exec, thread1's transaction fails. On failure, use UNWATCH to release locks, then reapply WATCH.
Java Integration
Jedis is the official Java client for Redis, offering APIs mirroring native commands. In Spring Boot 2.x+, Jedis is replaced by Lettuce. Jedis uses direct connections, which can be unsafe in multithreaded environments; Jedis Pool mitigates this with a connection pool (BIO-style). Lettuce employs netty for thread-safe instance sharing, reducing thread counts (NIO-style).
When using RedisTemplate, serialization is required for objects to avoid errors; JSON is acceptable. Non-serialized objects may cause encoding issues.
Redis Configuration File (redis.conf)
# Units are case-insensitive (e.g., 1GB, 1gB, 1gb).
# Include other config files, similar to Spring imports.
# Network settings:
bind 127.0.0.1 # Bind IP
port 6379 # Port
# General settings:
daemonize yes # Run as daemon (default no)
pidfile /var/run/redis_6379.pid # PID file for daemon
loglevel notice # Log level
databases 16 # Default 16 databases
# Snapshotting for persistence:
save 900 1 # Persist if 1+ key changes in 900s
save 300 10 # Persist if 10+ keys change in 300s
save 60 10000 # Persist if 10000+ keys change in 60s
stop-writes-on-bgsave-error yes # Halt writes on persistence error
rdbcompression yes # Compress RDB files (CPU cost)
rdbchecksum yes # Verify RDB file integrity
# Replication for master-slave:
# slaveof <masterip> <masterport> # Set as slave (e.g., slaveof 127.0.0.1 6379)
# Security (password):
# requirepass foobared # Default no password; set e.g., requirepass mypass
# Client limits:
# maxclients 10000 # Max client connections
# maxmemory <bytes> # Max memory capacity
# maxmemory-policy noeviction # Policy on memory limit (e.g., evict keys)
# Append-only mode (AOF):
appendonly no # Default off, uses RDB
appendfilename "appendonly.aof" # AOF file name
# appendfsync always # Sync every write (high performance cost)
appendfsync everysec # Sync per second (may lose 1s data)
# appendfsync no # OS-managed sync (fastest)
RDB and AOF Persistence
RDB
Periodically writes memory snapshots to disk, loading the snapshot file directly for recovery. Used in master-slave replication for backups on slaves.
Trigger conditions:
- Meeting save rules automatically triggers RDB.
- FLUSHALL command triggers RDB.
- Exiting Redis generates an RDB file (dump.rdb).
Recovery:
- Place dump.rdb in Redis startup directory; Redis auto-recovers data on launch.
- Check location with
config get dir; if dump.rdb exists there, data restores on startup.
Advantages: Suitable for large-scale recovery; tolerant of data loss. Disadvantages: Potential loss of recent changes on crash; fork process consumes resources. Default configuration is generally sufficient.
AOF
Logs all write commands (not reads) in an append-only file, re-executing them for recovery. Files rewrite at 64MB instead of appending.
Advantages: Better data integrity with per-modification sync; default per-second sync may loose 1s data; no-sync option is fastest. Disadvantages: Larger files than RDB; slower repair and operational efficiency.
If both RDB and AOF are enabled, AOF loads first during recovery due to superior integrity.
Redis Pub/Sub
Use cases include real-time chat, subscription systems, and messaging. For complex scenarios, message queues (MQ) are preferable.