1.先配置spring-data-redis

首先是依赖

    <dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.4.RELEASE</version>
</dependency>

redisconfig 配置类

@Configuration
@PropertySource("classpath:irongbei.properties")
public class RedisConfig extends JCacheConfigurerSupport {
@Autowired
private Environment environment; @Bean
public RedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory fac = new JedisConnectionFactory();
fac.setHostName(environment.getProperty("redis.host"));
fac.setPort(Integer.parseInt(environment.getProperty("redis.port")));
fac.setPassword(environment.getProperty("redis.password"));
fac.setTimeout(Integer.parseInt(environment.getProperty("redis.timeout")));
// fac.getPoolConfig().setMaxIdle(Integer.parseInt(environment.getProperty("redis.maxIdle")));
// fac.getPoolConfig().setMaxTotal(Integer.parseInt(environment.getProperty("redis.maxTotal")));
// fac.getPoolConfig().setMaxWaitMillis(Integer.parseInt(environment.getProperty("redis.maxWaitMillis")));
// fac.getPoolConfig().setMinEvictableIdleTimeMillis(
// Integer.parseInt(environment.getProperty("redis.minEvictableIdleTimeMillis")));
// fac.getPoolConfig()
// .setNumTestsPerEvictionRun(Integer.parseInt(environment.getProperty("redis.numTestsPerEvictionRun")));
// fac.getPoolConfig().setTimeBetweenEvictionRunsMillis(
// Integer.parseInt(environment.getProperty("redis.timeBetweenEvictionRunsMillis")));
// fac.getPoolConfig().setTestOnBorrow(Boolean.parseBoolean(environment.getProperty("redis.testOnBorrow")));
// fac.getPoolConfig().setTestWhileIdle(Boolean.parseBoolean(environment.getProperty("redis.testWhileIdle")));
return fac;
} @Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, String> redis = new RedisTemplate<>();
// 设置redis的String/Value的默认序列化方式
DefaultStrSerializer defaultStrSerializer = new DefaultStrSerializer();
redis.setKeySerializer(defaultStrSerializer);
redis.setValueSerializer(defaultStrSerializer);
redis.setHashKeySerializer(defaultStrSerializer);
redis.setHashValueSerializer(defaultStrSerializer);
redis.setConnectionFactory(redisConnectionFactory);
redis.afterPropertiesSet();
return redis;
}
} class DefaultStrSerializer implements RedisSerializer<Object> {
private final Charset charset; public DefaultStrSerializer() {
this(Charset.forName("UTF8"));
} public DefaultStrSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
} @Override
public byte[] serialize(Object o) throws SerializationException {
return o == null ? null : String.valueOf(o).getBytes(charset);
} @Override
public Object deserialize(byte[] bytes) throws SerializationException {
return bytes == null ? null : new String(bytes, charset); }
}

redisLock类 分布式锁实现的类

@Component
public class RedisLock { private static final Logger log = LoggerFactory.getLogger(RedisLock.class); @Autowired
private RedisTemplate<String, String> redisTemplate; /**
*
* @param key
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key,String value){ if(redisTemplate.opsForValue().setIfAbsent(key,value)){
log.info(" [Redis分布式锁] key:[{}] 获取到锁",key);
return true;
}
//oldvalue 俩个线程都返回A
String currentValue = redisTemplate.opsForValue().get(key);
//如果锁过期->这里如果一个key的value时间是小于当前当前时间 那就是过期了,如果大于当前时间才没有过期
if(StringUtils.isNotEmpty(currentValue) && Long.parseLong(currentValue) <System.currentTimeMillis()){ //获取上一个锁的时间
//第一个线程获取上一个oldvalue 然后设置一个新的值进去 第二个线程就获取到是新的值.
String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
//3 这一步就只有第一个线程能匹配到了 第二个线程就获取不到了
if(StringUtils.isNotEmpty(oldValue) && oldValue.equals(currentValue)){
log.info(" [Redis分布式锁] key:[{}] 获取到锁",key);
return true;
} } return false; } /**
* 解锁
* @param key
* @param value
*/
public void unlock(String key ,String value){
try {
String currentValue = redisTemplate.opsForValue().get(key);
if(StringUtils.isNotEmpty(currentValue) && currentValue.equals(value)){
redisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Exception e) {
log.error(" [redis分布式锁] 解锁异常, {} ",e);
} }
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"/spring-context.xml","/spring-context-jedis.xml","/spring-context-shiro.xml"})
public class RedisLockTest {
@Resource(name = "threadPoolTaskExecutor")
private ThreadPoolExecutor taskExecutor; @Autowired
private RedisLock redisLock;
private long timeout = 5*1000; private static final Logger logger =LoggerFactory.getLogger(RedisLockTest.class); @Test
public void test (){
for (int i = 0; i <200 ; i++) {
taskExecutor.execute(()->{
String time = String.valueOf(System.currentTimeMillis()+timeout);
if(!redisLock.lock("testlock",time)){
logger.info("哎呦喂..人太多了 在排队中..");
return;
}else {
try {
Thread.sleep(4000);
redisLock.unlock("testlock",time);
} catch (InterruptedException e) {
e.printStackTrace();
}
} });
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}

补充

和同事讨论,结果确实如同事所说,解锁的时候有些不严谨,因为是分俩步操作的.可能会在del之前被别人获取到锁然后再del删除掉别人获取的锁.下面是新的解锁方式,目前有些公司redis服务器不支持这样的命令

  为什么使用lua语言在操作Redis 主要是保证操作的原子性.一步操作

  但是使用lua要非常小心,如果脚本错误可能会阻塞整个Redis实例

 private static final Long SUCCESS = 1L;
/**
* 释放锁
* @param key
* @param value
* @return
*/
public boolean releaseLock(String key, String value) {
key =prifix+key;
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; RedisScript<String> redisScript = new DefaultRedisScript<>(script, String.class); try {
Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
System.out.println(result);
if (SUCCESS.equals(result)) {
log.info("[redis 分布式锁解锁成功] key:[{}] 结果:{}",key,result);
return true;
}
log.info("[redis 分布式锁解锁失败] key:[{}] 结果{}",key,result);
} catch (Exception e) {
log.info("[redis 分布式锁解锁失败] key:[{}] msg:{}",key,e.getMessage());
e.printStackTrace();
} return false;
}

 测试代码

    @Test
public void testPrefix(){
redisLock.lock("test","10000");
redisLock.lock("test1","10000");
// redisLock.lock("test2","10000");
// redisLock.lock("test3","10000");
redisLock.releaseLock("test","10000");
redisLock.releaseLock("test1","10002");
}

springMVC 实现redis分布式锁的更多相关文章

  1. Lua脚本在redis分布式锁场景的运用

    目录 锁和分布式锁 锁是什么? 为什么需要锁? Java中的锁 分布式锁 redis 如何实现加锁 锁超时 retry redis 如何释放锁 不该释放的锁 通过Lua脚本实现锁释放 用redis做分 ...

  2. 利用redis分布式锁的功能来实现定时器的分布式

    文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...

  3. Redis分布式锁

    Redis分布式锁 分布式锁是许多环境中非常有用的原语,其中不同的进程必须以相互排斥的方式与共享资源一起运行. 有许多图书馆和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都 ...

  4. redis分布式锁和消息队列

    最近博主在看redis的时候发现了两种redis使用方式,与之前redis作为缓存不同,利用的是redis可设置key的有效时间和redis的BRPOP命令. 分布式锁 由于目前一些编程语言,如PHP ...

  5. redis咋么实现分布式锁,redis分布式锁的实现方式,redis做分布式锁 积极正义的少年

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  6. spring boot redis分布式锁

    随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁.分布式锁的实现有很多种,比如基于数据库. zookeeper 等,本文主要介绍使用 Redis 做分布式锁的方式,并封装成spring b ...

  7. Redis分布式锁的正确实现方式

    前言 分布式锁一般有三种实现方式:1. 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁.本篇博客将介绍第二种方式,基于Redis实现分布式锁.虽然网上已经有各种介 ...

  8. Redis分布式锁---完美实现

    这几天在做项目缓存时候,因为是分布式的所以需要加锁,就用到了Redis锁,正好从网上发现两篇非常棒的文章,来和大家分享一下. 第一篇是简单完美的实现,第二篇是用到的Redisson. Redis分布式 ...

  9. redis分布式锁实践

    分布式锁在多实例部署,分布式系统中经常会使用到,这是因为基于jvm的锁无法满足多实例中锁的需求,本篇将讲下redis如何通过Lua脚本实现分布式锁,不同于网上的redission,完全是手动实现的 我 ...

随机推荐

  1. 从fastjson多层泛型嵌套解析,看jdk泛型推断

    给你一组json数据结构,你把它解析出来到项目中,你会怎么做? // data1 sample { "code" : "1", "msg" ...

  2. qml demo分析(objectlistmodel-自定义qml数据)

    一.效果展示 如图1所示,是一个ListView窗口,自定义了文本内容和项背景色. 图1 ListView 二.源码分析 代码比较简单,主要使用了QQmlContext类的setContextProp ...

  3. 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. 3.1 概述 说起垃圾收集(Garbage Collection,GC),大部分人都把这 ...

  4. MyX5TbsDemo【体验腾讯浏览服务Android SDK (完整版)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 按照官网上的说明:可独立下载x5内核,也可共享使用微信或手Q的x5内核. 本Demo在引用腾讯X5内核的基础上进行了封装.参考< ...

  5. 机器学习——随机森林,RandomForestClassifier参数含义详解

    1.随机森林模型 clf = RandomForestClassifier(n_estimators=200, criterion='entropy', max_depth=4) rf_clf = c ...

  6. springboot~zuul实现网关

    网关在微服务里的角色 在微服务架构体系里,网关是非常重要的一个环节,它主要实现了一些功能的统一处理,包括了: 统一授权 统一异常处理 路由导向 跨域处理 限流 实践一下 1 添加依赖 dependen ...

  7. Redis协议规范(RESP)

    Redis 即 REmote Dictionary Server (远程字典服务): 而Redis的协议规范是 Redis Serialization Protocol (Redis序列化协议) 该协 ...

  8. Asp.Net Core 轻松学-利用xUnit进行主机级别的网络集成测试

    前言     在开发 Asp.Net Core 应用程序的过程中,我们常常需要对业务代码编写单元测试,这种方法既快速又有效,利用单元测试做代码覆盖测试,也是非常必要的事情:但是,但我们需要对系统进行集 ...

  9. 第一册:lesson 121.

    原文:The man in a hat. question:Why didn't Caroline  recognize the customer straight away? I bought tw ...

  10. 持续集成-jenkins介绍与环境搭建

    什么是持续集成? 转自:https://blog.csdn.net/tanshizhen119/article/details/80328523 持续集成,俗称CI, 大师Martin Fowler对 ...