Redis 解决分布式锁 很nice

利用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 );

        */
        
    }

以上有问题的地方请大家多提意见,欢迎一同探讨探讨

猜你喜欢

转载自blog.csdn.net/fewefgds/article/details/107717051
今日推荐