Redis分布式锁,基于StringRedisTemplate和基于Lettuce实现setNx
使用redis分布式锁,来确保多个服务对共享数据操作的唯一性
一般来说有StringRedisTemplate和RedisTemplate两种redis操作模板。
根据key-value的类型决定使用哪种模板,如果k-v均是String类型,则使用StringRedisTemplate,否则使用RedisTemplate
redis加锁操作
必须遵循原子性操作,保证加锁的唯一性
核心方法
set(lockKey,value,"NXXX","EXPX",expireTime)
NXXX:只能取NX或者XX,NX-key不存在时进行保存,XX-key存在时才进行保存
EXPX:过期时间单位 (EX,PX),EX-秒,PX-毫秒
使用StringRedisTemplate实现加锁
public class StringRedisTemplateImplClient {
// NX,XX
//NX-key不存在则保存,XX-key存在则保存
private static final String STNX= "NX";
//EX,PX
//EX-秒,PX-毫秒
private static final String SET_EXPIRE_TIME = "PX";
private RedisTemplate redisTemplate;
private StringRedisTemplate stringRedisTemplate;
public StringRedisTemplateImplClient(RedisTemplate redisTemplate){
this.redisTemplate = redisTemplate;
this.stringRedisTemplate = new StringRedisTemplate();
this.stringRedisTemplate.setConnectionFactory(redisTemplate.getConnectionFactory());
this.stringRedisTemplate.afterPropertiesSet();
}
public StringRedisTemplateImplClient(StringRedisTemplate redisTemplate){
this.stringRedisTemplate = redisTemplate;
}
public boolean addRedisLock(String lockKey,String requestId,long expireTime){
boolean result = stringRedisTemplate.opsForValue()
.setIfAbsent(lockKey,lockKey,expireTime, TimeUnit.SECONDS);
return result;
}
}
下面简要分析下这个方法的一致性,查看setIfAbsent的源码
setIfAbsent这个方法是spring-data-redis提供的,分析其源码,实现类为org.springframework.data.redis.core.DefaultValueOperations
方法如下:
key-需要加锁的key
value-需要加锁的value
timeout-失效的时间
timeunit-常量,指定失效的时间单位
connection默认为lettuce驱动连接(springboot 2.0以后的版本)
public Boolean setIfAbsent(K key, V value, long timeout, TimeUnit unit) {
byte[] rawKey = this.rawKey(key);
byte[] rawValue = this.rawValue(value);
Expiration expiration = Expiration.from(timeout, unit);
return (Boolean)this.execute((connection) -> {
return connection.set(rawKey, rawValue, expiration, SetOption.ifAbsent());
}, true);
}
其中SetOption为指定NX/XX类型
public static enum SetOption {
UPSERT,
SET_IF_ABSENT,
SET_IF_PRESENT;
private SetOption() {
}
public static RedisStringCommands.SetOption upsert() {
return UPSERT;
}
public static RedisStringCommands.SetOption ifPresent() {
return SET_IF_PRESENT;
}
public static RedisStringCommands.SetOption ifAbsent() {
return SET_IF_ABSENT;
}
}
查询spring官网查询这三个属性
SET_IF_ABSENT--->NX
SET_IF_PRESENT--->XX

自定义实现SetNx
setNx+expireTime实现加锁
核心代码
String status = stringRedisTemplate.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
Object nativeConnection = connection.getNativeConnection();
String status = null;
RedisSerializer<String> stringRedisSerializer = (RedisSerializer<String>) stringRedisTemplate.getKeySerializer();
byte[] keyByte = stringRedisSerializer.serialize(key);
//springboot 2.0以上的spring-data-redis 包默认使用 lettuce连接包
//lettuce连接包,集群模式,ex为秒,px为毫秒
if (nativeConnection instanceof RedisAdvancedClusterAsyncCommands) {
logger.debug("lettuce Cluster:---setKey:"+setKey+"---value"+value+"---maxTimes:"+expireSeconds);
status = ((RedisAdvancedClusterAsyncCommands) nativeConnection)
.getStatefulConnection().sync()
.set(keyByte,keyByte,SetArgs.Builder.nx().ex(30));
logger.debug("lettuce Cluster:---status:"+status);
}
//lettuce连接包,单机模式,ex为秒,px为毫秒
if (nativeConnection instanceof RedisAsyncCommands) {
logger.debug("lettuce single:---setKey:"+setKey+"---value"+value+"---maxTimes:"+expireSeconds);
status = ((RedisAsyncCommands ) nativeConnection)
.getStatefulConnection().sync()
.set(keyByte,keyByte, SetArgs.Builder.nx().ex(30));
logger.debug("lettuce single:---status:"+status);
}
return status;
}
});
logger.debug("getLock:---status:"+status);//执行正确status="OK"
Redis分布式锁,基于StringRedisTemplate和基于Lettuce实现setNx的更多相关文章
- 分布式锁与实现(一)——基于Redis实现 【比较靠谱】
转: 分布式锁与实现(一)——基于Redis实现 概述 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统 ...
- RedLock.Net - 基于Redis分布式锁的开源实现
工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...
- 基于SpringBoot AOP面向切面编程实现Redis分布式锁
基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...
- SpringBoot集成Redis分布式锁以及Redis缓存
https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...
- 死磕 java同步系列之redis分布式锁进化史
问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...
- 掌握Redis分布式锁的正确姿势
本文中案例都会在上传到git上,请放心浏览 git地址:https://github.com/muxiaonong/Spring-Cloud/tree/master/order-lock 本文会使用到 ...
- Redis分布式锁—Redisson+RLock可重入锁实现篇
前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...
- Redis分布式锁—SETNX+Lua脚本实现篇
前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...
- Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!(转)
基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本篇文章主要是基于我们实际项目中因为redis分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...
随机推荐
- Ubuntu 12.04 安装 vsftpd
本篇文章由:http://xinpure.com/ubuntu-12-04-install-vsftpd/ 安装背景 wordpress 在线升级需要配置 ftp 帐号,之前用的是虚拟主机,都是带有 ...
- spring boot 在什么时候启动的tomcat
我一直很好奇 spring boot 以哪种方式 启动的 tomcat 今天 特地跟踪了一下 大家都知道 spring 容器很核心的 方式 是org.springframework.context. ...
- 【剑指Offer面试题】 九度OJ1510:替换空格
c/c++ 中的字符串以"\0"作为结尾符.这样每一个字符串都有一个额外字符的开销. 以下代码将造成内存越界. char str[10]; strcpy(str, "01 ...
- layui更新表格单元格数据口,更新单元格的内容
//监听工具条 table.on('tool(edit)', function(obj){ var data = obj.data; if(obj.event === 'getinvitation') ...
- [Informix] unload load
select tabname from systables where tabname like 'aa%' select * from syscolumns where tabname like ...
- [svc]visio绘制模具
visio2016狮子XL自定义运维模具下载: https://github.com/lannyMa/scripts/blob/master/%E7%BE%8E%E5%8C%96%E5%AE%9A%E ...
- python内置函数之print()
定义:将值打印到一个流对象,或者默认打印到sys.stdout. 语法: print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=Fal ...
- jMiniLang设计思路
前言 项目地址:https://github.com/bajdcc/jMiniLang 演示视频:https://www.bilibili.com/video/av13294962 jMiniLang ...
- onResume
比如做一个音乐播放程序,在播放过程中,突然有电话打进来了,这时系统自动调出电话,而你的音乐播放程序置于后台,触发了onPause方法.当你电话结束后,关闭电话,又自动回到音乐播放程序,此时,触发onR ...
- Spring MVC添加支持Http的delete、put请求!(HiddenHttpMethodFilter)
浏览器form表单只支持GET与POST请求,而DELETE.PUT等method并不支持,spring3.0添加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET.POST.PUT ...