Designing Idempotent Payment Callback Interfaces: Strategies and Implementation

The article explains the concept of idempotency and presents five practical designs—plain processing, JVM lock, pessimistic lock, optimistic lock, and unique‑constraint approaches—illustrated with Alipay recharge callback examples and SQL/Java code to ensure reliable, duplicate‑free payment handling in distributed backend systems.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Designing Idempotent Payment Callback Interfaces: Strategies and Implementation

What Is Idempotency?

For the same business operation, no matter how many times it is invoked, the result remains identical.

Idempotency Design Example

Using an Alipay recharge scenario, we analyze how to design a payment callback interface. Alipay sends a callback containing out_trade_no (merchant order number) and trade_no (Alipay transaction number), both unique in their respective systems.

Method 1 (Plain Approach)

Process flow:

1. Receive Alipay success request 2. Query the order by trade_no to see if it has been processed 3. If processed, return; otherwise continue 4. Open a local transaction 5. Credit the user’s account 6. Mark the order as successful 7. Commit the transaction

If multiple notifications arrive simultaneously, step 2 may see the order as unprocessed for each request, leading to duplicate credits. This method only works for single‑node, sequential processing.

Method 2 (JVM Lock)

To avoid the concurrency issue, a Java Lock is introduced:

1. Receive Alipay success request 2. Acquire a Java Lock 3. Query the order by trade_no 4. If processed, return; otherwise continue 5. Open a local transaction 6. Credit the user 7. Mark the order as successful 8. Commit the transaction 9. Release the lock

Analysis: The lock works only within a single JVM. In a clustered deployment, different instances handle concurrent callbacks, rendering the lock ineffective, so a distributed lock is required.

Method 3 (Pessimistic Lock)

Uses a database pessimistic lock ( FOR UPDATE) to serialize access:

select * from t_order where order_id = trade_no for update;

Process:

1. Receive request 2. Open transaction 3. Query the order with FOR UPDATE 4. If processed, return; otherwise continue 5. Credit the user 6. Mark order as successful 7. Commit transaction

The lock guarantees exclusive access but can cause thread contention under high concurrency, reducing throughput.

Method 4 (Optimistic Lock)

Relies on an optimistic‑lock column (e.g., status) in the database:

select * from t_order where order_id = trade_no;

Process:

1. Receive request 2. Query order 3. If processed, return; otherwise continue 4. Open transaction 5. Credit the user 6. Update with condition status = 0:

update t_order set status = 1 where order_id = trade_no where status = 0;

The update returns the affected row count; if it is 1 the update succeeded and the transaction is committed, otherwise it is rolled back. This mimics a CAS operation.

Method 5 (Unique‑Constraint Approach)

Creates a table with a unique key on ( ref_type, ref_id) to guarantee a single processing record:

CREATE TABLE `t_uq_dipose` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `ref_type` varchar(32) NOT NULL DEFAULT '' COMMENT 'Associated object type',
  `ref_id` varchar(64) NOT NULL DEFAULT '' COMMENT 'Associated object ID',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_1` (`ref_type`,`ref_id`) COMMENT 'Ensure business uniqueness'
) ENGINE=InnoDB;

Processing flow:

1. Receive request 2. Query t_uq_dipose for the given ref_type and ref_id 3. If a record exists, the order is already processed; otherwise continue 4. Open transaction, credit the user, mark order successful 5. Insert a record into t_uq_dipose; if the insert succeeds, commit, else roll back.

Because the unique constraint allows only one successful insert, concurrent attempts result in all but one failing, guaranteeing idempotency. For high‑traffic scenarios, table sharding may be needed to avoid bottlenecks.

Summary

Common idempotency implementations include pessimistic lock (FOR UPDATE), optimistic lock, and unique‑constraint methods. The recommended order of preference is: Optimistic lock > Unique constraint > Pessimistic lock. The article encourages discussion and sharing.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

lockingpayment
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

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.