Idempotency: Definition, Scenarios, and Implementation Strategies
The article explains the concept of idempotency, distinguishes it from duplicate submissions, outlines typical use cases such as network retries and form resubmissions, and presents various backend solutions—including unique indexes, deduplication tables, pessimistic and optimistic locks, distributed locks, and token‑based approaches—complete with SQL examples.
1 Idempotency
1.1 Definition
Idempotence originates from mathematics, meaning that applying a transformation N times yields the same result as applying it once. In engineering it describes that multiple identical requests produce the same outcome without side‑effects, regardless of how many times the user clicks.
The first request may cause a side‑effect, but subsequent identical requests must not change the resource.
Idempotence cares about the absence of side‑effects on later requests, not about the returned result.
Network time‑outs are outside the scope of idempotence discussion.
Idempotence is a service‑level promise: a successful call may be retried any number of times and the system’s state remains consistent.
1.2 Scenarios
Typical situations include network jitter causing lost responses and automatic retry mechanisms, or front‑end glitches that lead to duplicate form submissions. For example, a shopping request may be processed successfully on the server but the client never receives the acknowledgment, prompting a user‑initiated refresh that could cause double charging.
Using MySQL as an example, only certain operations need explicit idempotency handling:
SELECT col1 FROM tab1 WHERE col2=2; -- always returns the same state, naturally idempotent.
UPDATE tab1 SET col1=1 WHERE col2=2; -- repeated successful updates leave the state unchanged, also idempotent.
UPDATE tab1 SET col1=col1+1 WHERE col2=2; -- each execution changes the state, not idempotent.Difference between duplicate submission and idempotency:
Duplicate submission occurs when the first request succeeded and the user manually repeats the operation, causing state changes that violate idempotency.
Idempotency is needed when the first request’s result is unknown (e.g., timeout) or failed, and the client retries to ensure the operation succeeded without creating additional state changes.
1.3 Idempotency Considerations
Implementing idempotency adds complexity to the server side. A service must at least:
Check the previous execution status; if none exists, treat it as the first request.
Guard the business logic that changes state against duplicate execution.
While idempotency simplifies client logic, it increases server logic and cost, so it should be applied only when the business scenario truly requires it.
2 Idempotency Solutions
2.1 Front‑End Guard
Disable or hide the submit button after a click. This is easy but can be bypassed by users who craft raw HTTP requests.
2.2 Unique Index
Create a unique index on the relevant columns. Insertion attempts that violate the index raise a DuplicateKeyException, indicating a repeat.
Method 1: Add a unique index and catch DuplicateKeyException.
Method 2: Use MySQL’s ON DUPLICATE KEY UPDATE to insert if absent or update if present.
Method 3: REPLACE INTO (deletes then inserts) – works only with a primary key or unique index and may rebuild indexes.
2.3 Deduplication Table
Store a request identifier in a dedicated MySQL table with a unique index. If insertion succeeds, continue processing; if it fails, the request has already been handled.
2.4 Pessimistic Lock
Use Java synchronized or Lock for single‑node scenarios. In distributed environments, employ a distributed lock (e.g., Redis). MySQL’s FOR UPDATE can also serialize access:
Thread A acquires the row lock with FOR UPDATE ; other threads wait.
The lock is released automatically upon transaction commit.
The drawback is that long‑running business logic can cause many threads to block, reducing overall concurrency.
2.5 Optimistic Lock
Add a version column to each row. When updating, include the current version in the WHERE clause; if the update count is zero, the request is a duplicate.
SELECT id, name, account, version FROM user WHERE id = 1412; // assume version = 10
UPDATE user SET account = account + 10, version = version + 1
WHERE id = 1412 AND version = 10;2.6 Distributed Lock
Use Redis SETNX as a lock. If SETNX succeeds, treat it as the first execution; otherwise, the request has already been processed.
2.7 Token Scheme
Two‑phase approach: (1) request a token from the payment system and store it in Redis before the order page; (2) during payment, the token is checked and removed, ensuring the request is processed only once.
References
MySQL operations: https://blog.csdn.net/qq_18975791/article/details/107285455
Idempotency discussion: https://mp.weixin.qq.com/s/v4CamZlqHP8gEmubzPme4g
Implementation guide: https://blog.csdn.net/wanglei303707/article/details/88298211
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.