分布式加锁
Posted 双子家的咸蛋蛋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分布式加锁相关的知识,希望对你有一定的参考价值。
在高并发的条件下许多地方都要用到分布式加锁, 传统的单体架构加锁synchronized, 以及无法满足多节点集群的模式了, 所以目前比较主流的应该用到第三方中间件来实现分布式加锁.
Redis的setNX加锁
命令格式
SETNX key value
将 key 的值设为 value,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
SETNX 是SET if Not eXists的简写。
返回值
返回整数,具体为
1,当 key 的值被设置
0,当 key 的值没被设置
例子
redis> SETNX mykey “hello” (integer) 1 redis> SETNX mykey “hello” (integer) 0 redis> GET mykey “hello” redis>
实现1 StringRedisTemplate
这个是基于setnx的一种实现, 不同的是加锁的结果返回的是布尔值, 在高级版中可以在加锁的同时设置超时时间, 有效避免死锁的问题.
依赖
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>2.1.5.RELEASE</version> </dependency>
代码
AccessToken oToken = null; StringRedisTemplate redisTemplate = new StringRedisTemplate();
boolean lockFlag = redisTemplate.opsForValue().setIfAbsent("access_token_" + appId, appSecrete, 15L, TimeUnit.SECONDS); if (lockFlag) { logger.info("加锁成功, 开始获取最新的token"); try { oToken = weixinUtil.getAccessToken_for_dist(appId, appSecrete); } finally { redisTemplate.delete("access_token_" + appId); logger.info("解锁成功."); } } else { logger.info("加锁失败, 返回旧的token"); }
注意事项:
由于想实现加锁的同时设置超时时间, 需要spring-redis-data的版本达到2.1以上, 这就需要jedis的版本至少达到目前最新的2.9, 而且springboot的版本也需要达到2.0以上.
如果springboot版本达不到要求, 则会报如下的错:
2019-06-06 10:45:15.697 [main] ERROR org.springframework.boot.SpringApplication - Application startup failed java.lang.NoSuchMethodError: org.springframework.data.repository.config.RepositoryConfigurationSource.getAttribute(Ljava/lang/String;)Ljava/util/Optional; at org.springframework.data.redis.repository.configuration.RedisRepositoryConfigurationExtension.registerBeansForRoot(RedisRepositoryConfigurationExtension.java:88) at org.springframework.data.repository.config.RepositoryConfigurationDelegate.registerRepositoriesIn(RepositoryConfigurationDelegate.java:116) at org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport.registerBeanDefinitions(AbstractRepositoryConfigurationSourceSupport.java:59) at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(ConfigurationClassBeanDefinitionReader.java:359) at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:143) at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116)
以上是关于分布式加锁的主要内容,如果未能解决你的问题,请参考以下文章