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分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...
随机推荐
- javascript 创建对象的几种方式
1. //基于已有对象扩充其属性和方法var object = new Object(); object.name = "zhangsan"; object.sayName = f ...
- 新浪微博XSS攻击事件
http://blog.csdn.net/terryzero/article/details/6575078 6月28日20时14分左右开始,新浪微博出现了一次比较大的XSS攻击事件.大量用户自动发送 ...
- Android成长之路-手势库的创建
手势库的创建: 使用SDK自带的例子GestureBuilder建立手势库,这个文件夹存在于android\android-sdk-windows \samples\android-10\Gest ...
- Oracle开发者守则
下面为Oracle大师级语录: Oracle Database developers should follow is to do everything they can in SQL. What t ...
- spring in action小结4.1
1 横切关注点:可以被描述为影响应用多处的功能.横切关注点可以被模块化为特殊的类,这些类被称为切面. 2 AOP自己的术语,通知(Advice).切点(pointcut).连接点(joinpoint) ...
- 权限管理系统(四):RBAC权限模型分类介绍
RBAC是Role-BasedAccess Control的英文缩写,意思是基于角色的访问控制.RBAC认为权限授权实际上是Who.What.How的问题.在RBAC模型中,who.what.how构 ...
- docker使用问题总结
1. docker报[Error response from daemon: Error running DeviceCreate (createSnapDevice) dm_task_run fai ...
- Linksys WRT54G2 V1刷ddwrt注意事项
关于DD-WRT和TOMATO下的应用就不多说了,反正其他能刷DD-WRT.TOMATO的路由器会有的功能,这台机器也都有,不过此机器刷TOMATO一定要刷ND版本的,因为5354的CPU是属于比较新 ...
- C语言 · 图形输出
算法提高 图形输出 时间限制:1.0s 内存限制:512.0MB 编写一程序,在屏幕上输出如下内容: X | X | X ---+---+--- | | ---+---+--- O ...
- PHP——分页显示数据库内容
test.php <?php header("Content-Type:text/html;charset=utf-8"); //加载分页类 include "pa ...