Optimistic Locking and Idempotency
Fast recall
Quick revision
Core answer
@Version field or HTTP If-Match validator rejects an update based on stale state, preventing lost updates. Idempotency prevents the same logical operation from executing twice. Robust APIs often use both: one operation key and one expected resource version.Interview-ready guide
Interview answer
Optimistic locking prevents a stale update from silently overwriting a newer one. Idempotency prevents the same logical command from executing twice. They are related because both matter during retries, but they compare different identities: optimistic locking checks the resource revision the client read, while idempotency checks the operation the client intended to run.
A JPA entity can declare a field such as @Version long version. If two editors read version 4, the first successful update advances it to version 5. The second editor still carries version 4, so the provider raises OptimisticLockException rather than erasing the first change. The check may be reported when changes are flushed or when the transaction commits, not necessarily on the setter or repository call.
At the HTTP boundary, the server can return ETag: "order-v7". The client sends If-Match: "order-v7" with a change. HTTP uses strong comparison for If-Match. If the condition is false, the server normally returns 412 Precondition Failed without applying the method. The RFC also permits success when the server can verify that the same user agent's requested change already succeeded. An ETag may come from entity version data, but it is a public representation validator, not automatically the database counter.
An idempotency key asks, “Has command confirm-42-K already run?” A version validator asks, “Is order 42 still the revision I edited?” The same command can touch several records or an external system, so one entity version cannot identify it. Two different commands also need different operation keys even when they start from the same order revision.
A confirmation endpoint can require both key confirm-42-K and If-Match: "order-v7". The key stops duplicate execution, while the validator stops confirmation based on stale order state. After an optimistic-lock failure, read the fresh resource and decide again; blindly retrying the old update repeats the same bad assumption. A JPA exception also needs deliberate API mapping because JPA itself does not choose the HTTP status.
Optimistic Locking and Idempotency
Direct Answer
Optimistic locking and idempotency solve related but different retry problems. A JPA @Version field or HTTP If-Match validator rejects an update based on stale state, preventing lost updates. Idempotency prevents the same logical operation from executing twice. Robust APIs often use both: one operation key and one expected resource version.
Deep Dive & Architecture
Imagine two editors read customer version 4. Both submit different addresses. Without a condition, the later write can silently erase the earlier one. Optimistic locking places version 4 in the update predicate. One transaction advances to version 5; the other finds that version 4 no longer exists and fails instead of losing data.
JPA's @Version is a persistence mechanism. An ETag is an HTTP validator for a representation. They can be related, but they are not automatically interchangeable: an ETag might hash several fields, and exposing a database counter can couple the API to storage. The server must define how the public validator is generated and checked.
Idempotency storage tracks a logical command and its result. The same command may touch several resources or an external system, so one entity version cannot identify it. Conversely, two different legitimate commands need different idempotency keys even if both start from the same resource version.
When an If-Match precondition is false, HTTP defines 412 Precondition Failed. A JPA exception discovered without an HTTP precondition is often exposed as a conflict response, but the API should choose and document the mapping rather than claiming the framework mandates one status. Both failure paths should return enough safe information for the client to refetch and decide.
Code Example
GET /orders/42 HTTP/1.1
Host: api.example.com
HTTP/1.1 200 OK
ETag: "order-v7"
Content-Type: application/json
{"id":42,"status":"draft"}
PATCH /orders/42 HTTP/1.1
If-Match: "order-v7"
Content-Type: application/merge-patch+json
{"status":"confirmed"}
If version 7 is no longer current, the precondition is false and the server normally returns 412 Precondition Failed before applying the PATCH. This protects the version assumption; an operation key is still needed if confirming has a separately repeatable side effect.
Check your understanding
Answer these without looking back at the article.
- What does JPA check when updating an entity with `@Version`?
- When should an API return `412 Precondition Failed`?
- Why does optimistic locking not replace an idempotency key?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.