分布式加锁

在高并发的条件下许多地方都要用到分布式加锁, 传统的单体架构加锁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)

猜你喜欢

转载自www.cnblogs.com/goujh/p/10984050.html