redis 判断存在性_Redis如何保证接口的幂等性?
原标题:Redis如何保证接口的幂等性?
在最近的一次业务升级中,遇到这样一个问题,我们设计了新的账户体系,需要在用户将应用升级之后将原来账户的数据手动的同步过来,就是需要用户自己去触发同步按钮进行同步,因为有些数据是用户存在自己本地的。那么在这个过程中就存在一个问题,要是因为网络的问题,用户重复点击了这个按钮怎么办?就算我们在客户端做了一些处理,在同步的过程中,不能再次点击,但是经过我最近的爬虫实践,要是别人抓到了我们的接口那么还是不安全的。
基于这样的业务场景,我就使用Redis加锁的方式,限制了用户在请求的时候,不能发起二次请求。
我们在进入请求之后首选尝试获取锁对象,那么这个锁对象的键其实就是用户的id,如果获取成功,我们判断用户时候已经同步数据,如果已同步,那么可以直接返回,提示用户已经同步,如果没有那么直接执行同步数据的业务逻辑,最后将锁释放,如果在进入方法之后获取锁失败,那么有可能就是在第一次请求还没有结束的时候,接着又发起了请求,那么这个时候是获取不到锁的,也就不会发生数据同步出现同步好几次的情况。
华丽的分割线
那么有了这个需求之后,我们就来用Redis实现以下这个代码。首先我们要知道我们要介绍一下Redis的一个方法。
那么我们想要用Redis做用户唯一的锁对象,那么它在Redis中应该是唯一的,而且还不应该被覆盖,这个方法就是存储成功之后会返回true,如果该元素已经存在于Redis实例中,那么直接返回false
setIfAbsent(key,value)
但是这中间又存在一个问题,如果在获取了锁对象之后,我们的服务挂了,那么这个时候其他请求肯定是拿不到锁的,基于这种情况的考虑我们还应该给这个元素添加一个过期时间,防止我们的服务挂掉之后,出现死锁的问题。
/**
* 添加元素
*
* @paramkey
* @paramvalue
*/
publicvoid set(Object key, Object value) {
if(key == null|| value == null) {return;}redisTemplate.opsForValue.set(key, value.toString);}
/*** 如果已经存在返回false,否则返回true** @paramkey* @paramvalue* @return*/publicBooleansetNx(Object key, Object value, LongexpireTime, TimeUnit mimeUnit) {
if(key == null|| value == null) {returnfalse;}returnredisTemplate.opsForValue.setIfAbsent(key, value, expireTime, mimeUnit);}
/*** 获取数据** @paramkey* @return*/publicObject get(Object key) {
if(key == null) {returnnull;}returnredisTemplate.opsForValue.get(key);}
/*** 删除** @paramkey* @return*/publicBooleanremove(Object key) {
if(key == null) {returnfalse;}
returnredisTemplate.delete(key);}
/*** 加锁** @paramkey* @paramwaitTime 等待时间* @paramexpireTime 过期时间*/publicBooleanlock(String key, LongwaitTime, LongexpireTime) {
String value = UUID.randomUUID.toString.replaceAll("-", "").toLowerCase;
Booleanflag = setNx(key, value, expireTime, TimeUnit.MILLISECONDS);
// 尝试获取锁 成功返回if(flag) {returnflag;} else{// 获取失败
// 现在时间long newTime = System.currentTimeMillis;
// 等待过期时间long loseTime = newTime + waitTime;
// 不断尝试获取锁成功返回while(System.currentTimeMillis < loseTime) {
BooleantestFlag = setNx(key, value, expireTime, TimeUnit.MILLISECONDS);if(testFlag) {returntestFlag;}
try{Thread.sleep(1000);} catch(InterruptedException e) {e.printStackTrace;}}}returnfalse;}
/*** 释放锁** @paramkey* @return*/publicBooleanunLock(Object key) {returnremove(key);}
我们整个加锁的代码逻辑已经写完了,我们来分析一下,用户在进来之后,首先调用lock尝试获取锁,并进行加锁,lock方法有三个参数分别是:key,waitTime就是用户如果获取不到锁,可以等待多久,过了这个时间就不再等待,最后一个参数就是该锁的多久后过期,防止服务挂了之后,发生死锁。
当进入lock之后,先进行加锁操作,如果加锁成功,那么返回true,再执行我们后面的业务逻辑,如果获取锁失败,会获取当前时间再加上设置的过期时间,跟当前时间比较,如果还在等待时间内,那么就再次尝试获取锁,直到过了等待时间。
注意:在设置值的时候,我们为了防止死锁设置了一个过期时间,大家一定要注意,不要等设置成功之后再去给元素设置过期时间,因为这个过程不是一个原子操作,等你刚设置成功之后,还没等设置过期时间成功,服务直接挂了,那么这个时候就会发生死锁问题,所以大家要保证存储元素和设置过期时间一定要是原子操作。
最后我们来写个测试类测试一下
@Testpublicvoidtest01(){String key = "uid:12011";
Boolean flag = redisUtil.lock(key, 10L, 1000L* 60);
if(!flag) {
// 获取锁失败System.err.println("获取锁失败");} else{
// 获取锁成功System.out.println("获取锁成功");}
// 释放锁redisUtil.unLock(key);}返回搜狐,查看更多
责任编辑:
redis 判断存在性_Redis如何保证接口的幂等性?相关推荐
- 高并发下如何保证接口的幂等性?
前言 接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题.本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考. 不知道你有没有遇到过这些场景: ...
- 高并发下如何保证接口的幂等性
前言 接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题.本文分享了一些 ,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考. 不知道你有没有遇到过这些场景: 有时我们在填写某些 f ...
- 如何保证接口的幂等性?
什么是幂等性?所谓幂等,就是任意多次执行所产生的影响均与一次执行的影响相同. 为什么会产生接口幂等性问题 在计算机应用中,可能遇到网络抖动,临时故障,或者服务调用失败,尤其是分布式系统中,接口调用失败 ...
- 如何保证接口的幂等性
如何保证接口的幂等性 什么是幂等性 幂等性是系统服务对外一种承诺,承诺只要调用接口成功,外部多次调用对系统的影响是一致的.声明为幂等的服务会认为外部调用失败是常态,并且失败之后必然会有重试. 通俗地说 ...
- redis 判断存在性_实战 | springboot+redis+拦截器 实现接口幂等性校验
来源:https://www.jianshu.com/p/6189275403ed 一.概念 幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次 比如: 订单接口, 不能 ...
- redis 判断存在性_springboot + redis + 注解 + 拦截器 实现接口幂等性校验
提醒:后面有些图片模糊,请点击原文查看清晰图片 一.概念 幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次 比如: 订单接口, 不能多次创建订单 支付接口, 重复支付同 ...
- redis 判断存在性_一口气说出四种幂等性解决方案,面试官露出了姨母笑~
什么是幂等性? 幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同. " 在计算机中编程中,一个幂等操作的特点是其任意多次执行所产生的影 ...
- 【接口幂等性】使用token,Redis保证接口幂等性
使用token保证接口幂等性 接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用. 举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功, ...
- 如何保证微服务接口的幂等性
在微服务架构下,我们在完成一个订单流程时经常遇到下面的场景: 一个订单创建接口,第一次调用超时了,然后调用方重试了一次 在订单创建时,我们需要去扣减库存,这时接口发生了超时,调用方重试了一次 当这笔订 ...
最新文章
- python编程 入门到实践-Python编程入门到实践(二)
- leetcode C++ 48. 旋转图像 给定一个 n × n 的二维矩阵表示一个图像。 将图像顺时针旋转 90 度。
- 前端学习(1149):变量let02
- php新闻添加图片,PHP操纵blob巧将图片存入ORACLE
- 最简单的jQuery程序
- 试翻译Output Cache Improvements in Orchard 1.9
- 基于多源数据画像的失败用例智能分析
- 阿里云大学:使用自然语言处理进行简历筛选 笔记
- STM32工作笔记0042---认识三极管的集电极,发射极,基极
- JPEG文件中的EXIF(上)
- 米兰•昆德拉 漂浮的一生
- 万条票房数据看2019春节档各地影院表现
- Unity3D游戏高性能战争迷雾系统实现
- [ECCV2018]Generating 3D faces using Convolutional Mesh Autoencoders
- 68000多只海洋动物、占地18.3万平米,这才是全球最大海洋水族馆该有的气势!...
- C++ nth_element 介绍
- 如何导出Navicat的数据库连接配置
- mysql强制走索引
- Windows11-Redis 最新安装教程
- UserAgent 解析, 在线api