How to Prevent Duplicate Submissions in Java APIs with Redis and Redisson Locks

This article explains why API debouncing is crucial for backend Java services, outlines which endpoints need protection, describes how to identify duplicate requests, and provides step‑by‑step implementations using Redis shared‑cache and Redisson distributed locks with concrete code examples and test results.

Architect
Architect
Architect
How to Prevent Duplicate Submissions in Java APIs with Redis and Redisson Locks

The author, an experienced backend Java developer, explains why API debouncing is essential to prevent duplicate submissions caused by user mistakes or network jitter.

Debounce is defined as preventing both user “hand shake” and network “shake”. The article lists interface types that typically need debouncing: user‑input APIs (e.g., search), button‑click APIs (e.g., form submit), and scroll‑load APIs (e.g., infinite scroll).

To decide whether two requests are duplicates, the author proposes three checks: a time interval threshold, comparison of key parameters, and optional URL comparison.

Distributed deployment strategies

Two concrete solutions are presented.

Shared cache : store a temporary key in Redis with SET_IF_ABSENT and an expiration time; if the key already exists the request is rejected.

Distributed lock : use Redisson’s RLock; acquire the lock with tryLock(), set the same expiration, and release it after the method finishes.

Both approaches rely on a unique lock key generated from annotated method parameters.

Implementation details

A custom @RequestLock annotation defines prefix, expiration, time unit and delimiter. Parameters marked with @RequestKeyParam are concatenated to form the key. The RequestKeyGenerator.getLockKey method reflects on method arguments and fields to build the key string.

For the Redis‑based solution, RedisRequestLockAspect uses StringRedisTemplate.execute with RedisCallback to call SET_IF_ABSENT. If the call returns false, a BizException with message “Your operation is too fast, please try later” is thrown.

For the Redisson‑based solution, RedissonRequestLockAspect obtains an RLock via redissonClient.getLock(lockKey), attempts tryLock(), sets the lock expiration, proceeds with the original method, and finally unlocks.

Test screenshots show the first request succeeding ("Add user success"), rapid repeated submissions being blocked with error BIZ‑0001, and later submissions succeeding after the lock expires.

Shared cache flow diagram
Shared cache flow diagram
Distributed lock flow diagram
Distributed lock flow diagram
First submission success screenshot
First submission success screenshot
Repeated submission blocked screenshot
Repeated submission blocked screenshot
Later submission success screenshot
Later submission success screenshot

The author notes that the lock alone does not guarantee idempotency; database unique constraints (e.g., a unique index on userPhone) and business‑level checks are still required. He also advises adding user‑specific information (user ID, IP) to the key in production to avoid false positives.

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.

BackendJavaRedisspringDistributed LockredissonDebounce
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.