Redis Tutorial 0/42 lessons ~6 min read Lesson 22

    Optimistic Locking

    Optimistic locking with WATCH detects concurrent modifications before MULTI/EXEC commits — read version, queue updates, abort if another client changed the key.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Optimistic locking with WATCH detects concurrent modifications before MULTI/EXEC commits — read version, queue updates, abort if another client changed the key. Inventory systems with low contention prefer retry over blocking locks.

    EXEC returning empty multi-bulk means conflict — re-read and retry with backoff. High contention on same key makes optimistic locking thrash; switch to pessimistic SET NX or Lua.

    Spring @Version on JPA is the ORM analog; WATCH is the Redis native pattern.

    Understanding the topic

    Key concepts

    • WATCH key — track changes until EXEC.
    • Read current state after WATCH.
    • MULTI queue writes based on read.
    • EXEC fails (nil) if watched key touched.
    • Retry loop with exponential backoff.
    • UNWATCH or EXEC/DISCARD clears watch.
    text
    sequenceDiagram
    Client->>Redis: WATCH key
    Client->>Redis: MULTI
    Client->>Redis: commands
    Client->>Redis: EXEC

    Step-by-step explanation

    1. Client WATCHes keys involved in decision.
    2. Reads values (GET/HGET) outside MULTI.
    3. MULTI queues dependent writes.
    4. EXEC runs only if watched keys unchanged.
    5. On nil, client retries from WATCH.

    Syntax reference

    Common commands

    • Minimize time between WATCH and EXEC.
    • Watch all keys your logic depends on.
    • Cap retries to avoid infinite loops.
    bash
    WATCH stock:sku42
    qty = GET stock:sku42
    # if qty >= 1 locally:
    MULTI
    DECR stock:sku42
    EXEC
    # retry if EXEC returned (nil)

    Informative example

    Decrement stock only if sufficient — retry on conflict:

    bash
    # Loop in application until EXEC succeeds or max retries
    WATCH inventory:widget
    GET inventory:widget
    MULTI
    DECRBY inventory:widget 1
    EXEC

    Production code wraps in while loop with max 3–5 retries. High-contention SKU → use Lua single script instead.

    Real-world use

    Real-world use cases

    • Low-contention inventory decrement.
    • Balance update with version check.
    • Config update with read-verify-write.
    • Counter adjust after read threshold.
    • Cart merge conflict resolution.

    Best practices

    • Short watch window — few commands in MULTI.
    • Max retry with jitter backoff.
    • Switch to Lua on hot keys.
    • Watch minimal key set.
    • Log retry rate — high rate signals design issue.
    • Don't WATCH across user think time.

    Common mistakes

    • Infinite retry on perpetual conflict.
    • Watching wrong keys — stale commits.
    • Using on flash-sale hot SKU — use Lua or queue.
    • Assuming EXEC nil is error not conflict signal.

    Advanced interview questions

    Q1BeginnerOptimistic vs pessimistic lock?
    Optimistic detect conflict at commit; pessimistic block others upfront (SET NX).
    Q2BeginnerEXEC returns nil meaning?
    Watched key changed — transaction aborted.
    Q3IntermediateWhen prefer WATCH over SET NX lock?
    Low contention, read-heavy decision before write.
    Q4IntermediateFlash sale inventory pattern?
    Lua DECR if >0 or dedicated queue — WATCH retries explode.
    Q5AdvancedImplement optimistic lock in Spring + Redis?
    WATCH + MULTI in RedisTemplate session callback; retry; or Lua for hot paths.

    Summary

    WATCH + MULTI/EXEC = optimistic concurrency.

    Ready to mark this lesson complete?Track your journey across the entire course.