利用Redis解决分布式锁问题
关于分布式锁的原因产生我就不一一列举了,我这边直接撸代码
1.maven依赖
<!-- 引入Redis依赖 springboot整合的,补齐吧-->
<!-- 定义公共资源版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<dependencies>
<!-- redis 主要是这个依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 阿里fastJson包, JSON转换-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions><!-- 去掉springboot默认配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <!-- 引入log4j2依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
2.yml信息
spring.redis.database= 5
spring.redis.host = 127.0.0.1
spring.redis.password:
spring.redis.port= 6379
spring.redis.timeout= 3000
spring.redis.jedis.pool.max-idle=500
spring.redis.jedis.pool.min-idle= 50
spring.redis.jedis.pool.max-active= 2000
spring.redis.jedis.pool.max-wait= 1000
spring.redis.jedis.pool.testOnBorrow= true
3.配置 RedisTemplate 配置类
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import javax.annotation.Resource;
/**
* redis配置
* 主要是配置Redis的序列化规则,用Jackson2JsonRedisSerializer替换默认的jdkSerializer
* @author zhangfanghao
* @version 1.0
* @date 2019-07-21 21:04
*/
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
// 使用Jackson2JsonRedisSerialize替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置key和value的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
4撸代码
@Resource
private RedisTemplate redisTemplate;
@RequestMapping("/setSuo")
public String getsuo() {
//Redis存的key值
String REDIS_THREAD_LOCK_AMAZON = "ycy-amazon";
//Redis存的key对应的值-----这个很重要
String orderInfoVO = "zhi";
//这里相当于
while(true){
//这里相当于key值没有插入进去,就会产生阻塞
//setIfAbsent(redis key值,key对用value,过期时间,时间单位秒)
//key对应value用来解决什么问题?下面会说
//过期时间防止每个线程没有释放锁,用户一直等
boolean isTrue= redisTemplate.opsForValue().setIfAbsent(REDIS_THREAD_LOCK_AMAZON ,orderInfoVO ,3,,TimeUnit.SECONDS);
if(isTrue){
//成功添加了锁,跳出循环
//业务逻辑代码
break;
}
}
//代码执行完要释放锁
//这样做有一个问题
//设置的过期时间为5秒 第一个用户A拿到了锁然后执行代码,这个代码因 为网络什么原因运行很慢,时间超过了5秒,然后锁自动释放了,另一个用户B拿到了锁,这个时候上个A用户代码执行完毕了,释放了锁,此时释放的锁是刚刚用户B拿到的锁
//这里写的不是很严谨,要严谨的话可以使用下面注释的代码,此处可以删掉
redisTemplate.delete(REDIS_THREAD_LOCK_AMAZON );
//怎么解决?
//就要用到上面的key 对应的value值了
//在删除之前先进行判断
//就是在手动删除之前进行一个判断,拿到此时key对应value是否等于你刚刚放进去的value,如果等于,则删除,不等于则return,但前提是这个value必须保证幂等性
//比如你A放进去的值为1,业务逻辑代码执行了5秒,自动过期时间为3秒,你的key,value删除了,然后第B用户创建时放进去的value=2,A那里执行判断时发现1!=2所有没有执行删除
//注意orderInfoVO不是一定的,我这里方便起见
/**if(redisTemplate.opsForValue().get(REDIS_THREAD_LOCK_AMAZON )!=orderInfoVO){
return;
}
redisTemplate.delete(REDIS_THREAD_LOCK_AMAZON );
*/
}
以上有问题的地方请大家多提意见,欢迎一同探讨探讨