使用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的更多相关文章

  1. 分布式锁与实现(一)——基于Redis实现 【比较靠谱】

    转: 分布式锁与实现(一)——基于Redis实现 概述 目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统 ...

  2. RedLock.Net - 基于Redis分布式锁的开源实现

    工作中,经常会遇到分布式环境中资源访问冲突问题,比如商城的库存数量处理,或者某个事件的原子性操作,都需要确保某个时间段内只有一个线程在访问或处理资源. 因此现在网上也有很多的分布式锁的解决方案,有数据 ...

  3. 基于SpringBoot AOP面向切面编程实现Redis分布式锁

    基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...

  4. SpringBoot集成Redis分布式锁以及Redis缓存

    https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...

  5. 死磕 java同步系列之redis分布式锁进化史

    问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...

  6. 掌握Redis分布式锁的正确姿势

    本文中案例都会在上传到git上,请放心浏览 git地址:https://github.com/muxiaonong/Spring-Cloud/tree/master/order-lock 本文会使用到 ...

  7. Redis分布式锁—Redisson+RLock可重入锁实现篇

    前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...

  8. Redis分布式锁—SETNX+Lua脚本实现篇

    前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...

  9. Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!(转)

    基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本篇文章主要是基于我们实际项目中因为redis分布式锁造成的事故分析及解决方案.我们项目中的抢购订单采用的是分布式锁来解决的,有一次,运营做了一 ...

随机推荐

  1. nginx代理tomcat

    http://blog.csdn.net/kongqz/article/details/6838989 http://www.800l.com/linux-nginx-tomcat-jdk.html ...

  2. pageEncoding和ContextType区别

    http://blog.csdn.net/kerrywang/article/details/4454895 pageEncoding        在JSP标准的语法中,如果 pageEncodin ...

  3. 利用Oracle 发送邮件(utl_smtp)

    发送邮件的方法有很多,.NET前台也可以通过创建邮件类的形式, 通过微软提供的System.Net.Mail.dll 也可以简单的发送邮件.但是代码比较长,操作起来虽然很简单(很多细节忽略了). 这里 ...

  4. PHP权限控制(转)

    PHP: 我这里说到的权限管理办法是一个普遍采用的方法,主要是使用到"位运行符"操作,& 位与运算符.| 位或运行符.参与运算的如果是10进制数,则会被转换至2进制数参与运 ...

  5. WCF学习之三, 寄宿方式 代码,配置文件

    可以通过代码或者配置文件寄宿WCF服务,在使用过程中的一些心得,记录一下,方便后续查阅. 预备知识,几个地址的作用 1. behavior.HttpGetUrl  定义元数据的地址,如果不定义基地址, ...

  6. USES_CONVERSION的使用和注意

    USES_CONVERSION是用来转换类型的,比如我们很常见的问题: 在Socket编程时候,我们的IP地址从界面上输进去一般都使用CString类型的,可是在SOCKADDR_IN中的inet_a ...

  7. stm32 堆和栈(stm32 Heap & Stack)

    关于堆和栈已经是程序员的一个月经话题,大部分有是基于os层来聊的. 那么,在赤裸裸的单片机下的堆和栈是什么样的分布呢?以下是网摘: 刚接手STM32时,你只编写一个 int main() { whil ...

  8. Django的ORM中如何判断查询结果是否为空,判断django中的orm为空

    result= Booking.objects.filter() #方法一 .exists() if result.exists(): print "QuerySet has Data&qu ...

  9. HDU 2844 Coin 多重背包

    Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  10. renderer:function参数介绍

    转载自:http://blog.sina.com.cn/s/blog_9eaf28f90101b7y3.html renderer:function(value, cellmeta, record, ...