Backend Development 10 min read

Ensuring Idempotency in Order Services: Preventing Duplicate Orders and Solving the ABA Problem

This article explains how to prevent duplicate order submissions and address the ABA concurrency issue by using database transactions, unique constraints, request identifiers, and version‑based optimistic locking to achieve reliable idempotent behavior in backend order services.

Architect's Guide
Architect's Guide
Architect's Guide
Ensuring Idempotency in Order Services: Preventing Duplicate Orders and Solving the ABA Problem

Problem Background

The simplest solution is to use a DB transaction: when creating an order, insert rows into the order table and order‑item table within the same transaction.

When the Order service calls the Pay service and a network timeout occurs, the Order service may retry, causing the Pay service to receive the same payment request twice on different nodes; thus a distributed interface must guarantee idempotency.

How to Avoid Duplicate Orders

Front‑end pages can prevent duplicate form submissions, but network errors and automatic retries in RPC frameworks or gateways can still cause repeated requests, so the core issue remains ensuring service‑side idempotency.

2.1 How to Determine a Request Is Duplicate

Before inserting an order, check the order table for duplicates, but defining “duplicate order” in SQL is difficult.

Is an order with the same user, product, and price a duplicate? What if the user intentionally places two identical orders?

To achieve idempotency, the following practices are required:

2.1.1 Each request must have a unique identifier

For example, a payment request should include an order ID, and an order ID can only be paid successfully once.

2.1.2 After processing a request, record that it has been handled

In MySQL, add a status field or insert a payment record before processing the payment.

2.1.3 When receiving a request, check whether it has been processed before

If an order has already been paid, a payment record exists; a duplicate request will attempt to insert a payment record with the same unique key, causing a duplicate‑key error and preventing double charging.

Using MySQL’s primary‑key uniqueness, an INSERT with an existing primary key will fail, so by providing the primary key on insert you can enforce idempotent order creation.

Generate a globally unique order number via an “orderId generation” API; the front‑end obtains this orderId before submitting the order, and the same orderId is used for all subsequent insert attempts, relying on the DB’s unique constraint.

In practice, combine this with Redis: store the orderId as a unique key, mark it as paid after a successful payment record insertion, and reject further payments for the same orderId.

When a duplicate payment request arrives, the Redis key order_id will have the value payed , indicating the order has already been processed.

If a duplicate order causes an INSERT into t_order to fail, the Order service should not return the error to the front‑end; otherwise the user may see a failure message even though the order was created.

Solution to the ABA Problem

ABA occurs when an order’s tracking number is updated twice (e.g., 666 then 888) and a retry of the earlier request reverts the data incorrectly.

3.2 Solution

Add a version column to the order table. Each query returns the current version, and the client includes this version in the update request.

When updating, compare the provided version with the stored version; if they match, perform the update and increment the version within the same transaction.

UPDATE orders set tracking_number = 666, version = version + 1 WHERE version = 8;

If the version has changed because another update occurred, the update fails, prompting the client to re‑fetch the latest version and retry.

This version‑based optimistic locking prevents both duplicate updates and ABA scenarios, ensuring the database state matches the user’s view.

Summary

Pre‑generate a unique order number and rely on the DB’s unique constraint to achieve idempotent order creation.

Use a version‑column mechanism for updates, checking the version and incrementing it atomically to solve the ABA problem and guarantee idempotent updates.

These two idempotency techniques can be applied to any service that persists data in a database with a primary‑key table.

backendIdempotencyorder serviceABA problemOptimistic Lockingdatabase transaction
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.