• SpringBoot整合Redisson实现分布式锁


    介绍

    分布式锁:指的是在某种高并发的业务情况下,保证数据一致性的锁,如:秒杀业务往往是高并发的,那么就有可能导致超卖的情况发生,此时就可以使用分布式锁来保证商品不会超卖

    原理

    具体原理是使用Redis缓存实现分布式锁,当大量用户请求资源时,保证资源的同步性,如上面的秒杀例子里,当用户请求时库存就要减一,此时我们就要保证高并发情况下,库存资源的同步访问

    注意分布式锁要存在统一的Redis缓存中,各服务统一访问该缓存获取锁访问共享资源

    Redisson实现分布式锁的原理

    在这里插入图片描述

    案例

    实现逻辑:先往Redis写入库存数据

    具体参考:

    SpringBoot操作Redis 一

    SpringBoot操作Redis 二

    @GetMapping("/miaosha/add")
    public String miaoshaAdd() {
    
        String key = "product:0";
    
        redisUtil.set(key, "100");
    
        return "miaosha add success";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ApiFox发送请求

    在这里插入图片描述

    Redis Desktop Manager查看数据,库存为100个

    在这里插入图片描述

    有了库存后,我们就可以模拟秒杀场景了,代码如下:

    POM

    
    <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.7.1version>
            <relativePath/> 
        parent>
        <groupId>com.examplegroupId>
        <artifactId>redisartifactId>
        <version>0.0.1-SNAPSHOTversion>
        <name>redisname>
        <description>redisdescription>
        <properties>
            <java.version>1.8java.version>
        properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
    
            
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-redisartifactId>
            dependency>
    
            
            <dependency>
                <groupId>org.redissongroupId>
                <artifactId>redissonartifactId>
                <version>3.16.8version>
            dependency>
    
            
            <dependency>
                <groupId>redis.clientsgroupId>
                <artifactId>jedisartifactId>
            dependency>
    
            
            <dependency>
                <groupId>org.apache.commonsgroupId>
                <artifactId>commons-collections4artifactId>
                <version>4.2version>
            dependency>
            <dependency>
                <groupId>cn.hutoolgroupId>
                <artifactId>hutool-coreartifactId>
                <version>5.3.10version>
            dependency>
    
            
            <dependency>
                <groupId>com.alibabagroupId>
                <artifactId>fastjsonartifactId>
                <version>1.2.69version>
            dependency>
    
        dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombokgroupId>
                                <artifactId>lombokartifactId>
                            exclude>
                        excludes>
                    configuration>
                plugin>
            plugins>
        build>
    
    project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    Yml

    redis:
      db: 0
      host: 192.168.61.4
      port: 6379
      password: psd
      timeout: 3000
      max-active: 100
      max-idle: 10
      min-idle: 10
      max-wait: 20000
    
    server:
      port: 80
    
    spring: # 允许循环依赖
      main:
        allow-circular-references: true
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    核心:通过Redisson的getLock方法生成的RLock对象的lock与unlock方法同步代码逻辑,这里的锁理论上来说是从Redis中查的,如果不存在就生成,一个共享资源对应唯一一个锁,各服务(线程)抢这把锁进行业务处理

    package com.example.redis.controller;
    
    import com.example.redis.config.R;
    import com.example.redis.util.RedisUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.redisson.Redisson;
    import org.redisson.api.RLock;
    import org.redisson.api.RedissonClient;
    import org.redisson.config.Config;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    
    /**
     * @description: miaosha
     * @author: zj
     * @date: 2022-07-27 17:21
     */
    @RestController
    @Slf4j
    public class MiaoShaController {
    
        @Resource
        private RedissonClient redission;
    
        @Resource
        private RedisUtil redisUtil;
    
        @GetMapping("/miaosha")
        public String miaosha() {
            String key = "key:product";
    
            RLock lock = redission.getLock(key);
            lock.lock();
    
            try {
                //减库存
                int stock = Integer.parseInt(redisUtil.get("product:0"));
                if (stock > 0) {
                    redisUtil.decrby("product:0", 1);
                    System.out.println("扣减成功,剩余库存:" + redisUtil.get("product:0"));
                } else {
                    return R.ok("stock is empty");
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
    
            lock.unlock();
            return R.ok("success");
        }
    
    
        @Bean
        public RedissonClient redissonClient() {
            Config config = new Config();
            config.useSingleServer().setAddress("redis://192.168.61.4:6379").setDatabase(0).setPassword("psd");
            return Redisson.create(config);
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    ApiFox模拟高并发访问接口测试用例,生成100个线程循环10次,模拟高并发接口请求

    在这里插入图片描述

    可以看到控制台是一个一个进行资源消费的,这样就实现了使用Redis的分布式锁

    在这里插入图片描述

    Redis里的数据也被消费完了

    在这里插入图片描述

  • 相关阅读:
    19.服务器端会话技术Session
    DirectX11 With Windows SDK--36 延迟渲染:基础
    吃透SpringBoo的这些t知识,你就已经超过90%的Java面试者了
    【补题日记】[2022杭电暑期多校3]K-Taxi
    二维数组根据某个字段进行分组
    实习三个月的感悟
    一文读懂 Spring Bean 的生命周期
    WEB前端 网页设计 简介
    一个最简verilog代码的分析
    [附源码]计算机毕业设计JAVAjsp高校奖学金评定管理系统
  • 原文地址:https://blog.csdn.net/weixin_41405524/article/details/126022503