Redis锁实现防重复提交和并发问题
@Slf4j
@Component
public class RedisLock { public static final int LOCK_EXPIRE = 5000; @Autowired
private StringRedisTemplate redisTemplate; /**
* 分布式锁
*
* @param key key值
* @return 是否获取到
*/
public boolean lock(String key) { String lock = key;
try {
return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
long expireAt = System.currentTimeMillis() + LOCK_EXPIRE;
Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
if (acquire) {
log.info("用户 [{}]加锁成功",key); return true;
} else {
log.info("用户 [{}]加锁失败",key); //判断该key上的值是否过期了
byte[] value = connection.get(lock.getBytes());
if (Objects.nonNull(value) && value.length > 0) {
long expireTime = Long.parseLong(new String(value));
if (expireTime < System.currentTimeMillis()) {
// 如果锁已经过期
byte[] oldValue = connection.getSet(lock.getBytes(), String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE).getBytes());
// 防止死锁
return Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
}
}
}
return false;
});
} finally {
RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
}
} /**
* 删除锁
*
* @param key
*/
public void delete(String key) {
try {
redisTemplate.delete(key);
} finally {
RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
}
}
//实现业务
try{
// 判断是否获取了锁
boolean getLock = redisLock(lockKey);
if(getLock){
// 此处可以开始写需要实现的代码
}
}catch(Exception e){
e.printStackTrace();
}finally {
// 判断是否超时了,如果未超时,则释放锁。 超时了,锁有可能被其他线程拿走了,就不做任何操作
redisLock.delete(String.valueOf(caronwerId));
}
}
知识点: redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。
设置成功,返回 1 。 设置失败,返回 0 。
redis> EXISTS job # job 不存在
(integer) 0 redis> SETNX job "programmer" # job 设置成功
(integer) 1 redis> SETNX job "code-farmer" # 尝试覆盖 job ,失败
(integer) 0 redis> GET job # 没有被覆盖
"programmer"
一.redis命令讲解:
setnx()命令:
setnx的含义就是SET if Not Exists,其主要有两个参数 setnx(key, value)。 该方法是原子的,如果key不存在,则设置当前key成功,返回1;如果当前key已经存在,则设置当前key失败,返回0。 get()命令:
get(key) 获取key的值,如果存在,则返回;如果不存在,则返回nil;
getset()命令:
这个命令主要有两个参数 getset(key, newValue)。该方法是原子的,对key设置newValue这个值,并且返回key原来的旧值。
假设key原来是不存在的,那么多次执行这个命令,会出现下边的效果:
1. getset(key, “value1”) 返回nil 此时key的值会被设置为value1
2. getset(key, “value2”) 返回value1 此时key的值会被设置为value2
3. 依次类推!
二.具体的使用步骤如下:
1. setnx(lockkey, 当前时间+过期超时时间) ,如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。
2. get(lockkey)获取值oldExpireTime ,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向3。
3. 计算newExpireTime=当前时间+过期超时时间,然后getset(lockkey, newExpireTime) 会返回当前lockkey的值currentExpireTime。
4. 判断currentExpireTime与oldExpireTime 是否相等,如果相等,说明当前getset设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。
5. 在获取到锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理
Redis锁实现防重复提交和并发问题的更多相关文章
- Java使用Redis实现分布式锁来防止重复提交问题
如何用消息系统避免分布式事务? - 少年阿宾 - BlogJavahttp://www.blogjava.net/stevenjohn/archive/2018/01/04/433004.html [ ...
- 浅谈C#在网络波动时防重复提交
前几天,公司数据库出现了两条相同的数据,而且时间相同(毫秒也相同).排查原因,发现是网络波动造成了重复提交. 由于网络波动而重复提交的例子也比较多: 网络上,防重复提交的方法也很多,使用redis锁, ...
- (亿级流量)分布式防重复提交token设计
大型互联网项目中,很多流量都达到亿级.同一时间很多的人在使用,而每个用户提交表单的时候都可能会出现重复点击的情况,此时如果不做好控制,那么系统将会产生很多的数据重复的问题.怎样去设计一个高可用的防重复 ...
- resubmit 渐进式防重复提交框架简介
resubmit resubmit 是一款为 java 设计的渐进式防止重复提交框架. 推荐阅读: 面试官:你们的项目中是怎么做防止重复提交的? resubmit 渐进式防重复提交框架简介 创作目的 ...
- (九)Struts2 防重复提交
所有的学习我们必须先搭建好Struts2的环境(1.导入对应的jar包,2.web.xml,3.struts.xml) 第一节:重复提交示例演示 struts.xml <?xml version ...
- AJAX防重复提交的办法总结
最近的维护公司的一个代理商平台的时候,客服人员一直反映说的统计信息的时候有重复数据,平台一直都很正常,这个功能是最近新进的一个实习生同事写的功能,然后就排查问题人所在,发现新的这个模块的AJAX提交数 ...
- SpringMVC后台token防重复提交解决方案
本文介绍如何使用token来防止前端重复提交的问题. 目录 1.思路 2.拦截器源码实现 3.注解源码 4.拦截器的配置 5.使用指南 6.结语 思路 1.添加拦截器,拦截需要防重复提交的请求 2.通 ...
- Spring MVC表单防重复提交
利用Spring MVC的过滤器及token传递验证来实现表单防重复提交. 创建注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RU ...
- struts2学习(15)struts2防重复提交
一.重复提交的例子: 模拟一种情况,存在延时啊,系统比较繁忙啊啥的. 模拟延迟5s钟,用户点了一次提交,又点了一次提交,例子中模拟这种情况: 这样会造成重复提交: com.cy.action.St ...
随机推荐
- win10 安装tensorflow2.0 GPU版本遇到的坑
背景:我的机器上tensorflow 1.14 & 2.0,这俩版本都有,之前都是用1.14版本,今天试一下2.0尝尝鲜, 结果就掉坑去了 把CUDA10.1 和 cudnn 安装 ...
- RNN神经网络产生梯度消失和梯度爆炸的原因及解决方案
1.RNN模型结构 循环神经网络RNN(Recurrent Neural Network)会记忆之前的信息,并利用之前的信息影响后面结点的输出.也就是说,循环神经网络的隐藏层之间的结点是有连接的,隐藏 ...
- SeekBar滑动时,progress数值不连续
问题描述 logcat 你是否也遇见过这样的情况,SeekBar的进度不连续 这是我在做一个编辑图片的APP时,观察我打印的log,发现progress不是连续的 这时候可能就有人问:是你代码写的不对 ...
- 《JavaScript语言入门教程》记录整理:运算符、语法和标准库
目录 运算符 算数运算符 比较运算符 布尔运算符 二进制位运算符 void和逗号运算符 运算顺序 语法 数据类型的转换 错误处理机制 编程风格 console对象和控制台 标准库 Object对象 属 ...
- 【av68676164(p43-p47)】物理内存管理
7.2.1 分区内存管理 把内存分为若干个区给用户使用 单一区存储管理 分区存储管理 固定分区 动态分区 单一区存储管理(不分区存储管理) 定义:用户区不分区,完全被一个程序占用.例如:DOS 优点: ...
- 一篇看懂Socket开发
Socket[套接字]是什么,对于这个问题,初次接触的开发人员一般以为他只是一个通讯工具. Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发 T ...
- C#LeetCode刷题之#404-左叶子之和(Sum of Left Leaves)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4084 访问. 计算给定二叉树的所有左叶子之和. 3 / ...
- 获取客户端用户真实ip方法整理(jekyll迁移)
layout: post title: 获取客户端用户真实ip方法整理 date: 2019-08-22 author: xiepl1997 tags: springboot 由请求获取客户端ip地址 ...
- webpack打包原理
什么是 webpack ? 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建一个依 ...
- node mssql 无法连接sql server
mssql无法连接sql server主要有两种原因: Sql server使用的是Windows身份验证 Sql server并没有打开网络连接功能 1.打开Sql Server身份验证 参考这篇文 ...