使用Redission实现接口防重复提交

博客介绍了Spring Boot接口防抖和幂等性的实现方法,包括定义注解Idempotent、定义切面、使用注解以及编写测试类,参考相关内容并做了简化,可轻松搞定接口重复提交问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、定义注解 Idempotent

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: 
 * @Description: 幂等注解 主要作用于方法和类上 作用在类上表示这个类里所有的方法都做限制
 * 如果要使用nacos配置文件,不要这里使用@ConfigurationProperties,而是应该再写一个类
 * 使用注解获取ncos的配置后,在切面里覆盖这个元数据
 * @Date: 2024/4/25
 **/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {

    /**
     * 幂等的超时时间,默认为 1 秒
     *
     * 注意,如果执行时间超过它,请求还是会进来
     */
    int timeout() default 3;

    /**
     * 时间单位,默认为 SECONDS 秒
     */
    TimeUnit timeUnit() default TimeUnit.SECONDS;

    /**
     * redis锁前缀
     * @return
     */
    String keyPrefix() default "submit:";

    /**
     * key分隔符
     * @return
     */
    String delimiter() default ":";

    /**
     * 提示信息,正在执行中的提示
     */
    String message() default "重复请求,请稍后重试";
}

二、定义切面

import lombok.SneakyThrows;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
imp
### 使用 Redisson 实现重复支付功能 为了止在分布式环境中发生重复支付的情况,可以利用 Redisson 提供的分布式锁机制来确保同一订单在同一时刻只会被处理一次。下面展示了一种基于 Redisson解决方案。 #### 创建 Redisson 客户端并初始化配置 首先定义一个 `Redisson` 配置对象,并指定连接到 Redis 服务的方式: ```java import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class PaymentService { private static final String LOCK_NAME_PREFIX = "payment-lock:"; public void init() { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); // 将 client 设置为类成员变量或其他合适位置以便后续使用 this.redisson = redisson; } } ``` #### 获取分布式锁以保护关键路径 当接收到支付请求时,在执行实际付款逻辑之前先尝试获取对应于特定订单ID的锁。这可以通过调用 `getLock()` 方法获得 RLock 对象完成,随后调用其 `tryLock()` 或者异步版本的方法尝试占有资源。 ```java public boolean processPayment(String orderId) throws InterruptedException { RLock lock = redisson.getLock(LOCK_NAME_PREFIX + orderId); try { if (!lock.tryLock()) { System.out.println("Failed to acquire the lock for order ID:" + orderId); return false; } // 执行具体的支付流程... performPayment(orderId); return true; } finally { unlock(lock, orderId); } } private void unlock(RLock lock, String orderId){ try{ if (lock.isHeldByCurrentThread()){ lock.unlock(); System.out.println("Released lock for order ID:" + orderId); } } catch(Exception e){ System.err.println("Error releasing lock for order ID:" + orderId); } } ``` 此代码片段展示了如何安全地锁定解锁给定订单号关联的数据项,从而避免并发条件下可能出现的竞争条件问题[^2]。 #### 自动续期(看门狗) 为了避免长时间持有锁而导致其他线程无法继续工作,通常会设定较短的有效期限;然而这样做可能会带来新的风险——即正常情况下事务未结束前就提前失去了所有权。为此,Redisson 内建了自动续约机制(`scheduleExpirationRenewal`),可以在有效期内周期性延长锁的时间直到显式释放为止[^3]。 通过以上措施,能够有效地保障每次支付操作都是唯一的,即使是在高负载环境下也能保持良好的一致性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘个Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值