[{"data":1,"prerenderedAt":448},["ShallowReactive",2],{"learn-concept-/learn/optimistic-concurrency":3},{"id":4,"title":5,"body":6,"date":386,"description":387,"domain":388,"domainKey":389,"extension":390,"featured":169,"fullName":207,"interaction":12,"maturity":391,"mentalModel":392,"meta":393,"navigation":169,"neighbors":394,"ogImage":424,"path":425,"published":169,"robots":424,"seo":426,"shortName":427,"sitemap":428,"sources":429,"stem":442,"tags":443,"translationKey":12,"updated":386,"__hash__":447},"learnEn/learn/optimistic-concurrency.md","Optimistic Concurrency",{"type":7,"value":8,"toc":376},"minimal",[9,13,17,20,25,33,46,54,58,61,82,123,126,137,141,148,181,188,192,270,273,281,284,288,291,308,311,315,318,321,325,351,355,372],[10,11,5],"h1",{"id":12},"optimistic-concurrency",[14,15,16],"p",{},"Optimistic Concurrency Control (OCC) solves a deceptively simple problem: two people can read the same record, make different changes, and accidentally erase each other's work.",[14,18,19],{},"Its defining move is not to lock the record while everyone thinks. It lets work proceed, then validates the writer's original assumption at the moment of commitment.",[21,22,24],"h2",{"id":23},"the-failure-it-prevents-lost-update","The failure it prevents: lost update",[14,26,27,28,32],{},"Suppose Alice and Bob both read document ",[29,30,31],"code",{},"#42"," at version 7.",[34,35,36,40,43],"ul",{},[37,38,39],"li",{},"Alice changes the title and saves first. The database advances to version 8.",[37,41,42],{},"Bob is still editing the old version 7. He changes the owner field and submits the whole object.",[37,44,45],{},"Without concurrency control, Bob's stale object can silently restore the old title.",[14,47,48,49,53],{},"That is a ",[50,51,52],"strong",{},"lost update",". The dangerous part is not that two people read together. It is that Bob's write was accepted even though the premise behind it was stale.",[21,55,57],{"id":56},"the-mechanism","The mechanism",[14,59,60],{},"OCC normally has three stages:",[62,63,64,70,76],"ol",{},[37,65,66,69],{},[50,67,68],{},"Read"," the business data and a concurrency token such as a version number or Entity Tag (ETag).",[37,71,72,75],{},[50,73,74],{},"Work"," locally without holding a long-lived exclusive lock.",[37,77,78,81],{},[50,79,80],{},"Validate and write"," as one atomic operation. If the token still matches, commit and advance it. If not, report a conflict.",[83,84,89],"pre",{"className":85,"code":86,"language":87,"meta":88,"style":88},"language-sql shiki shiki-themes dracula","UPDATE documents\nSET title = 'Q3 Growth Plan',\n    version = version + 1\nWHERE id = 42\n  AND version = 7;\n","sql","",[29,90,91,99,105,111,117],{"__ignoreMap":88},[92,93,96],"span",{"class":94,"line":95},"line",1,[92,97,98],{},"UPDATE documents\n",[92,100,102],{"class":94,"line":101},2,[92,103,104],{},"SET title = 'Q3 Growth Plan',\n",[92,106,108],{"class":94,"line":107},3,[92,109,110],{},"    version = version + 1\n",[92,112,114],{"class":94,"line":113},4,[92,115,116],{},"WHERE id = 42\n",[92,118,120],{"class":94,"line":119},5,[92,121,122],{},"  AND version = 7;\n",[14,124,125],{},"One affected row means version 7 was still current. Zero affected rows means the record changed after it was read.",[14,127,128,129,132,133,136],{},"The comparison and write must be atomic. A separate ",[29,130,131],{},"SELECT"," followed later by an unconditional ",[29,134,135],{},"UPDATE"," leaves a Time of Check to Time of Use (TOCTOU) race between the two statements.",[21,138,140],{"id":139},"the-same-idea-in-http","The same idea in HTTP",[14,142,143,144,147],{},"Hypertext Transfer Protocol (HTTP) exposes this pattern with Entity Tag (ETag) and ",[29,145,146],{},"If-Match",":",[83,149,153],{"className":150,"code":151,"language":152,"meta":88,"style":88},"language-http shiki shiki-themes dracula","GET /documents/42\nETag: \"v7\"\n\nPUT /documents/42\nIf-Match: \"v7\"\n","http",[29,154,155,160,165,171,176],{"__ignoreMap":88},[92,156,157],{"class":94,"line":95},[92,158,159],{},"GET /documents/42\n",[92,161,162],{"class":94,"line":101},[92,163,164],{},"ETag: \"v7\"\n",[92,166,167],{"class":94,"line":107},[92,168,170],{"emptyLinePlaceholder":169},true,"\n",[92,172,173],{"class":94,"line":113},[92,174,175],{},"PUT /documents/42\n",[92,177,178],{"class":94,"line":119},[92,179,180],{},"If-Match: \"v7\"\n",[14,182,183,184,187],{},"If the resource is no longer version 7, the server can reject the write with ",[29,185,186],{},"412 Precondition Failed",". The condition is evaluated where the write happens, not guessed by the client from an earlier read.",[21,189,191],{"id":190},"optimistic-versus-pessimistic","Optimistic versus pessimistic",[193,194,195,211],"table",{},[196,197,198],"thead",{},[199,200,201,205,208],"tr",{},[202,203,204],"th",{},"Dimension",[202,206,207],{},"Optimistic Concurrency Control",[202,209,210],{},"Pessimistic Concurrency Control",[212,213,214,226,237,248,259],"tbody",{},[199,215,216,220,223],{},[217,218,219],"td",{},"Default assumption",[217,221,222],{},"Conflicts are uncommon",[217,224,225],{},"Conflicts are likely or very costly",[199,227,228,231,234],{},[217,229,230],{},"Control point",[217,232,233],{},"Validate at commit",[217,235,236],{},"Lock or queue before work",[199,238,239,242,245],{},[217,240,241],{},"No-conflict cost",[217,243,244],{},"Little waiting",[217,246,247],{},"Lock and waiting overhead remain",[199,249,250,253,256],{},[217,251,252],{},"Conflict cost",[217,254,255],{},"Retry, merge, or discard work",[217,257,258],{},"Usually wait rather than redo",[199,260,261,264,267],{},[217,262,263],{},"Common risks",[217,265,266],{},"Retry storms, livelock, poor conflict UX",[217,268,269],{},"Deadlocks, timeouts, lower throughput",[14,271,272],{},"A useful approximation is:",[83,274,279],{"className":275,"code":277,"language":278,"meta":88},[276],"language-text","optimistic cost ≈ validation + conflict probability × redo cost\npessimistic cost ≈ locking + waiting + deadlock/timeout handling\n","text",[29,280,277],{"__ignoreMap":88},[14,282,283],{},"Real systems often mix them: optimistic editing for ordinary records, short locks or queues for a few hot resources, and idempotency keys around external side effects.",[21,285,287],{"id":286},"conflict-is-part-of-the-protocol","Conflict is part of the protocol",[14,289,290],{},"Detecting a conflict is only half the design. The product must decide what happens next:",[34,292,293,296,299,302,305],{},[37,294,295],{},"reject and ask the user to refresh;",[37,297,298],{},"re-read and retry a deterministic operation;",[37,300,301],{},"merge independent fields;",[37,303,304],{},"show a three-way merge;",[37,306,307],{},"serialize a hot resource through a queue or short transaction.",[14,309,310],{},"Automatic retry also needs idempotency, bounded retries, and backoff with jitter. Retrying an operation that sends money, email, or third-party requests can otherwise duplicate the side effect.",[21,312,314],{"id":313},"where-it-fits","Where it fits",[14,316,317],{},"OCC is strongest when reads dominate writes, conflicts are rare, users may edit for a long time, and retry or merge is affordable.",[14,319,320],{},"It degrades when many requests fight over one hot record, conflicts invalidate expensive work, or a business invariant spans records that a single version token cannot protect.",[21,322,324],{"id":323},"what-it-is-not","What it is not",[34,326,327,333,339,345],{},[37,328,329,332],{},[50,330,331],{},"Not Last Write Wins."," OCC makes stale writes visible instead of silently accepting the last arrival.",[37,334,335,338],{},[50,336,337],{},"Not Multi-Version Concurrency Control (MVCC)."," MVCC mainly answers which version a reader sees; OCC answers whether a writer's premise is still current.",[37,340,341,344],{},[50,342,343],{},"Not Compare-and-Swap (CAS)."," CAS is an atomic primitive that can implement the broader OCC strategy.",[37,346,347,350],{},[50,348,349],{},"Not Optimistic User Interface."," Optimistic UI changes perceived latency; OCC protects concurrent correctness.",[21,352,354],{"id":353},"five-things-to-keep","Five things to keep",[62,356,357,360,363,366,369],{},[37,358,359],{},"OCC means “do not block first; validate the premise at commit.”",[37,361,362],{},"The check and write must be atomic.",[37,364,365],{},"Version, ETag, and CAS are carriers or mechanisms, not the complete policy.",[37,367,368],{},"A conflict needs a designed exit: reject, retry, merge, or serialize.",[37,370,371],{},"Choose between waiting and rework based on contention and failure cost, not ideology.",[373,374,375],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":88,"searchDepth":101,"depth":101,"links":377},[378,379,380,381,382,383,384,385],{"id":23,"depth":101,"text":24},{"id":56,"depth":101,"text":57},{"id":139,"depth":101,"text":140},{"id":190,"depth":101,"text":191},{"id":286,"depth":101,"text":287},{"id":313,"depth":101,"text":314},{"id":323,"depth":101,"text":324},{"id":353,"depth":101,"text":354},"2026-07-16","Work in parallel; reject stale writes before they overwrite newer changes.","Software systems","software-systems","md","growing","Let people work in parallel; when someone commits, verify that the assumptions they started from are still true.",{},[395,399,404,409,414,419],{"name":396,"fullName":210,"category":397,"summary":398},"PCC","strategy","Acquire exclusive access before doing the critical work, trading retries for waiting and lock management.",{"name":400,"fullName":401,"category":402,"summary":403},"MVCC","Multi-Version Concurrency Control","storage model","Keep multiple versions so readers can see a consistent snapshot without blocking writers.",{"name":405,"fullName":406,"category":407,"summary":408},"CAS","Compare-and-Swap / Compare-and-Set","atomic primitive","Replace a value only when it still equals the expected value; a common building block for OCC.",{"name":410,"fullName":411,"category":412,"summary":413},"Isolation","Transaction Isolation","semantics","Defines what concurrent transactions may observe and which anomalies the database prevents.",{"name":415,"fullName":416,"category":417,"summary":418},"Idempotency","Idempotent Operation","retry safety","Makes a repeated request produce the intended effect once, which is essential before automatic retries.",{"name":420,"fullName":421,"category":422,"summary":423},"OT / CRDT","Operational Transformation / Conflict-free Replicated Data Type","merge model","Preserves concurrent intent by transforming or converging operations instead of simply rejecting one writer.",null,"/learn/optimistic-concurrency",{"title":5,"description":387},"OCC",{"loc":425},[430,433,436,439],{"title":431,"url":432},"RFC 9110 · HTTP Semantics: If-Match","https://www.rfc-editor.org/rfc/rfc9110.html#name-if-match",{"title":434,"url":435},"PostgreSQL · Concurrency Control","https://www.postgresql.org/docs/current/mvcc.html",{"title":437,"url":438},"Microsoft · Handling Concurrency Conflicts in EF Core","https://learn.microsoft.com/en-us/ef/core/saving/concurrency",{"title":440,"url":441},"AWS · Optimistic locking with version number","https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/BestPractices_OptimisticLocking.html","learn/optimistic-concurrency",[444,445,446],"concurrency","databases","distributed-systems","JJ1NPrTjvToRfI9O9OMD4s_CRQGYU-aJ2Um7nvpJgz8",1784318363942]