• Redisson实现分布式锁


      业务场景:商品秒杀减库存操作

    一、先简单创一个springBoot项目

     

     pom.xml加入依赖

    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.dengfeng</groupId>
        <artifactId>webprojectDemo-springboot</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.4.0.RELEASE</version>
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- 热部署 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>    
            <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson</artifactId>
                <version>3.6.5</version>
            </dependency>
    
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.8.1</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-redis</artifactId>
                <version>2.2.5.RELEASE</version>
            </dependency>
    
    
        </dependencies>
    </project>

    创建配置文件application.yml

    server:
      port: 8100

    新建2个类,IndexController,和启动类StartApplication

    StartApplication

    package com.dengfeng.lock;
    
    
    
    import org.redisson.Redisson;
    import org.redisson.config.Config;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    
    
    
    @SpringBootApplication
    public class StartApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(StartApplication.class, args);
        }
        
        //实例化一个redisson客户端,redisson框架主要解决分布式锁时间设置问题
        @Bean
        public Redisson redisson() {
            Config config=new Config();
            config.useSingleServer().setAddress("redis://localhost:6379").setDatabase(0);
            return (Redisson)Redisson.create(config);
        }
    
    }

    IndexController

    package com.dengfeng.lock;
    
    import java.util.UUID;
    import java.util.concurrent.TimeUnit;
    
    import org.redisson.Redisson;
    import org.redisson.api.RLock;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /*
     * 使用redisson实现分布式锁
     */
    @RestController
    public class IndexController {
        
        private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
        
        @Autowired
        private Redisson redisson;
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
        
        @RequestMapping("/getStock")
        public String deductStock() {
            String lockKey="lockKey";        
            RLock redissonLock = redisson.getLock(lockKey);
            int stock;
            try {    
                //synchronized锁是锁在jvm,集群环境下不适用,redisson锁在redis,redis底层是单线程
                //加锁redissonLock.lock,底层设置了锁,默认时间30秒,stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "dengfeng",30, TimeUnit.SECONDS); =jedis.setnx(key,value);无key添加成功,有key不能添加              
                //底层开启了定时续命分线程。加锁后,只有一条线程能执行以下业务代码,其他线程会等待该线程释放资源,会在当前位置阻塞
                //分线程每隔10秒检查是否还持有锁,如果持有则延长锁的时间,间隔10秒不是固定,取锁时间的1/3
                //底层用lua脚本判断是否有相同key,锁时间,加锁其实就是设置key,value
                redissonLock.lock();
                
                //高并发多条线程进来时,
                stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            
                if(stock>0) {
                    int realStock=stock-1;
                    stringRedisTemplate.opsForValue().set("stock", realStock+"");
                    System.out.println("redis数据库扣减成功:库存剩余"+realStock);
                }else {
                    System.out.println("库存不足,扣减失败");
                }                    
            } finally{        
                redissonLock.unlock();             //释放锁
            }
            
            return String.valueOf(stock);
        }
        
        
        
        @RequestMapping("/dengfeng")
        public String deductStock1() {
            
            return "dengfeng123456";
        }
    
    }

    以上代码加锁完成,下面是原理图和底层代码

    加锁原理图如下

    底层采用lua脚本将字符串返回给redis,使用redis原子性,要么都成功,要么都不成功 

    附:AOP原理加锁

      为了不影响原有业务和代码冗余等,我想通过注解+AOP使用redisson加锁,在每个接口上通过如下注解

          参考文章:https://www.cnblogs.com/qq1728209643/p/10050191.html

  • 相关阅读:
    Valid Parentheses
    Remove Nth Node From End of List
    守护线程、守护进程
    4Sum
    Letter Combinations of a Phone Number
    3sum closest
    Excel Sheet Column Number
    Majority Element
    Balanced Binary Tree
    Maximum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/binghuaZhang/p/14430030.html
Copyright © 2020-2023  润新知