redis实现接口幂等性

1. 说明

幂等性的概念:任意多次执行所产生得影响均与一次执行的影响相同,对数据库的影响只能是一次性的,不能重复处理。在实际项目中,在客户端没限制幂等性,重复调用接口,导致接口数据重复写入数据。
解决接口幂等性有多种方式,建立数据库唯一索引,乐观锁或悲观锁,程序先查询后判断,唯一标识机制等。本文介绍使用redis生成唯一标识来限制接口重复提交,实现接口幂等性。

redis实现流程图:

2. 实现

引入依赖

  <!-- 使用springboot --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency>

yml文件配置

# 添加redis 配置
redis:database: 1host: 127.0.0.1port: 6379timeout: 6000ms  # 连接超时时长(毫秒)jedis:pool:max-active: 1000  # 连接池最大连接数max-wait: -1ms      # 连接池最大阻塞等待时间max-idle: 10      # 连接池中的最大空闲连接min-idle: 5       # 连接池中的最小空闲连接

redisUtil工具类

@Component
public class RedisUtil {@Autowiredprivate RedisTemplate redisTemplate;/*** 写入缓存** @param key* @param value* @return*/public boolean set(final String key, Object value) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.set(key, value);result = true;} catch (Exception e) {e.printStackTrace();}return result;}/*** 写入缓存设置时间** @param key* @param value* @param expireTime* @return*/public boolean setEx(final String key, Object value, long expireTime) {boolean result = false;try {ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();operations.set(key, value);redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);result = true;} catch (Exception e) {e.printStackTrace();}return result;}/*** 读取缓存** @param key* @return*/public Object get(final String key) {Object result = null;ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();result = operations.get(key);return result;}/*** 删除对应的value** @param key*/public boolean remove(final String key) {if (exists(key)) {Boolean delete = redisTemplate.delete(key);return delete;}return false;}/*** 判断key是否存在** @param key* @return*/public boolean exists(final String key) {boolean result = false;ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();if (Objects.nonNull(operations.get(key))) {result = true;}return result;}
}

注解引入,自定义注解,自定义注解作用是使用该注解的方法实现幂等性。通过反射机制扫描到该注解就会在方法上实现自动幂等,使用ElementType.METHOD只能作用在方法上。

@Target({ElementType.METHOD})//作用到方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {}

创建生成唯一标识方法,后台使用uuid生成唯一标识,存入redis中,并设置过期时间。

        //使用uuid为redis的keyString ideMark = UUID.randomUUID().toString();//存入redis 设置过期时间为一天 24 * 60 * 60 * 1000boolean flag = redisUtil.setEx(ideMark.toString(), ideMark.toString(), 60*1000);if (!flag) {throw new ApiException(ApiCode.REPEAT_OPERATION);}return ideMark;

校验唯一标识,从请求头获取校验幂等的唯一标识,并查找redis,若查询到了,则删除redis中的唯一标识,放行方法业务逻辑,若查询不到redis,则重复请求。

//从请球头获取String ideMark = request.getHeader(IDEA_MARK);// 请求头header中不存在ideMarkif (StringUtils.isEmpty(ideMark)) {throw new ApiException(ApiCode.REPEAT_OPERATION);//return false;}// ideMark从redis查询不到if (!redisUtil.exists(ideMark)) {throw new ApiException(ApiCode.REPEAT_OPERATION);//return false;}//删除redis中的keyboolean remove = redisUtil.remove(ideMark);if (!remove) {throw new ApiException(ApiCode.REPEAT_OPERATION);//return false;}return true;

拦截器

/*** 拦截器的配置:配置幂等性拦截器处理 AuthInterceptor*/
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {@Beanpublic AuthInterceptor authInterceptor() {return new AuthInterceptor();}/*** 拦截器配置** @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(authInterceptor());super.addInterceptors(registry);}//静态资源拦截@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {super.addResourceHandlers(registry);}
}

拦截处理:扫描拦截到注解@Idempotent方法,调用校验方法校验唯一标识是否正确,若失败则抛出异常信息。

@Slf4j
public class AuthInterceptor extends HandlerInterceptorAdapter {@Autowiredprivate IdeMarkService ideMarkService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;//获取到方法Method method = handlerMethod.getMethod();//被@Idempotent注解标记的扫描Idempotent methodAnnotation = method.getAnnotation(Idempotent.class);if (methodAnnotation != null) {ideMarkService.checkIdeMark(request);// 幂等性校验, 校验通过则放行, 校验失败则抛出异常}return true;}}

编写测试接口

/*** redis 使用幂等性*/
@RestController
@RequestMapping("/ide/mark")
public class IdeMarkController {@Autowiredprivate IdeMarkService ideMarkService;/*** 创建幂等性标识* @return*/@GetMapping("/createIdeMark")public Object createIdeMark(){return RData.ok(ideMarkService.createIdeMark());}/*** 测试幂等性* @return*/@Idempotent@GetMapping("/test/Idempotence")public Object testIdempotence() {String ideMark = "幂等测试成功";return RData.ok(ideMark) ;}
}

测试校验幂等性,先获取唯一标识,将唯一标识存到调用业务代码的header里面,再调用业务方法测试接口幂等性。

第一次调用业务方法

第二次调用业务方法

3.总结

本文介绍使用redis实现接口幂等性,主要使用redis数据存入,注解拦截处理,校验redis的key,实现逻辑比较简单,实现写入数据接口幂等性十分重要,在接口被客户端调用时,在不影响业务逻辑的情况,保证数据不重复写入数据数据库,防止脏数据和乱数据的写入。

github上源码:
https://github.com/wenxiangmeng/idempotent

redis实现接口幂等性相关推荐

  1. 太好了 | 这篇写的太好了!Spring Boot + Redis 实现接口幂等性

    Hi ! 我是小小,今天是本周的第四篇,第四篇主要内容是 Spring Boot + Redis 实现接口幂等性 介绍 幂等性的概念是,任意多次执行所产生的影响都与一次执行产生的影响相同,按照这个含义 ...

  2. 【SpringBoot应用篇】SpringBoot+Redis实现接口幂等性校验

    [SpringBoot应用篇]SpringBoot+Redis实现接口幂等性校验 幂等性 解决方法 Pom token令牌 yml @ApiIdempotentAnn ApiIdempotentInt ...

  3. Spring Boot + Redis 实现接口幂等性 | 分布式开发必知!

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 来源:http://tinyurl.com/y5k2sx5t >>阿里云8月最新 ...

  4. Sprinig Boot + Redis 实现接口幂等性,写得太好了!

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:收藏了!7 个开源的 Spring Boot 前后端分离优质项目个人原创+1博客:点击前往,查看更多 作者:wa ...

  5. springboot幂等性_SpringBoot+Redis实现接口幂等性,就看这篇了

    介绍 幂等性的概念是,任意多次执行所产生的影响都与一次执行产生的影响相同,按照这个含义,最终的解释是对数据库的影响只能是一次性的,不能重复处理.手段如下 数据库建立唯一索引 token机制 悲观锁或者 ...

  6. Redis 处理接口幂等性的两种方案

    前言:接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题.对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦重复了,可能会导致很严重的 ...

  7. 【接口幂等性】使用token,Redis保证接口幂等性

    使用token保证接口幂等性 接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用. 举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功, ...

  8. 乐观锁实现接口幂等性_calvin-idempotent

    自定义注解,基于Redis实现接口幂等性 一.幂等性概念 幂等(idempotent.idempotence)是一个数学与计算机学概念,常见于抽象代数中. 在编程中,一个幂等操作的特点是其任意多次执行 ...

  9. Springboot + redis + 注解 + 拦截器来实现接口幂等性校验

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:wangzaiplus www.jianshu.com/p/ ...

最新文章

  1. android 学习随笔十七(服务 )
  2. 我给非洲医药基金会捐的款和感谢信
  3. Spring源码解析——如何阅读源码
  4. Pandas-DataFrame基础知识点总结
  5. 数字滤波器(六)--设计FIR滤波器
  6. 2013年11月17日
  7. 想要拥有自己的jar包吗?------超级简单的打jar包教程~~~
  8. bzoj 1048: [HAOI2007]分割矩阵(记忆化搜索)
  9. 创建Maven web工程不能解析EL表达式的解决办法
  10. ORACLE关联查询
  11. Atitit.创业之uke团队规划策划 v9
  12. 数据库(基础SQL)
  13. STM32中RTC唤醒停止模式
  14. 同行评审就是个笑话!Nature爆料:计算机生成的垃圾文章竟还能被接受,64%来自中国...
  15. windows和linux双系统
  16. 《Android FFmpeg 播放器开发梳理》第一章 播放器初始化与解复用流程
  17. 欧姆龙PLC和FANUC发那科DeviceNet通讯
  18. 【考研初试】问题汇总及解答
  19. vue项目导入谷歌字体包
  20. SVM用于上证指数的预测

热门文章

  1. 图像去黑边 MATLAB
  2. 递归 谢尔宾斯基三角形
  3. 日常数据库练习题(每天进步一点点系列)
  4. Arduino 按钮矩阵 原理
  5. tec控制pid程序_如何设计TEC 温度环路 PID 控制电路?这个方法告诉你
  6. Oracle数据库从入门到精通系列之二:SGA和后台进程
  7. Linux安装JMeter进行压力测试
  8. mysql front和navicat_Navicat for MySQL与MySQL-Front比较
  9. css实现液晶字体效果
  10. chk文件恢复和文件恢复的区别有哪些?