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分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...
随机推荐
- Android自动化框架
Android自动化框架 已有 2085 次阅读2014-8-26 12:19 | Android 几种常见的Android自动化测试框架及其应用 随着Android应用得越来越广,越来越多的公司推出 ...
- 转:sock_ev——linux平台socket事件框架(uri地址的解析) .
在第一篇中,已经说明,传递的socket地址采取以下形式: [cpp] view plaincopyprint?stream://192.168.2.10:8080 dgram://192.168 ...
- ZOJ 3427 Array Slicing (scanf使用)
题意 Watashi发明了一种蛋疼(eggache) 语言 你要为这个语言实现一个 array slicing 函数 这个函数的功能是 有一个数组初始为空 每次给你一个区间[ l, r) 和 ...
- windows上通过secureCRT和putty创建密钥登录
前面介绍了linux的ssh远程登录协议和ssh无password登录方式.这里在windows下通过secureCRT和putty登录linux来看一下详细的密钥创建,配置和登录.也算做个备忘录吧. ...
- Ajax异步打开新页面弹框被拦截,无法将参数值传递到后台
一.Form提交,打开新页面被拦截 手动触发Form提交打开新页面是不会被拦截的,但是如果通过Ajax异步处理回调后再程序自动触发Form提交的话,就会被浏览器当成广告弹框拦截 1.暂时的解决办法:如 ...
- 统计重复字符串 如 eeefffkkkhjk 得到如下结果 3e3f3khjk;
//统计重复字符串 如 eeefffkkkhjk 得到如下结果 3e3f3khjk; string zipStr = Console.ReadLine(); var charList = zipStr ...
- 雅虎天气API调用
雅虎天气API调用: 1.调用方法:http://weather.yahooapis.com/forecastrss?w=2502265&u=c,绿色字体为城市代号,u=c表示取摄氏度. 2. ...
- 微服务Spring Cloud与Kubernetes比较
转 http://www.tuicool.com/articles/VnMf2y3 Spring Cloud或Kubernetes都宣称它们是开发运行微服务的最好环境,哪个更好?答案是两个都是,但他们 ...
- JavaScript:Object.prototype.toString进行数据类型判定
在JavaScript中,想要判断某个对象值属于哪种内置类型,最靠谱的做法就是通过Object.prototype.toString方法. var arr = []; console.log(Obje ...
- mplayer 全屏问题
[root@ok home]# gedit ~/.mplayer/config # Write your default config options here! zoom=yes #加上这个参数!全 ...