springboot配置集成RedisTemplate和Redisson,使用分布式锁案例

news/2024/7/3 0:40:06

文章要点

  • 自定义配置属性类
  • 集成配置RedisTemplate
  • 集成配置分布式锁Redisson
  • 使用分布式锁简单实现超卖方案

1. 项目结构

在这里插入图片描述

2. 集成RedisTemplate和Redisson

添加依赖
依赖的版本与继承的spring-boot-starter-parent工程相对应,可写可不写

<!--spring data redis & cache-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- redis依赖commons-pool 这个依赖一定要添加 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <!--redisson-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.15.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

大概图解

在这里插入图片描述如上图,先配置application.yml设置Redis的各项属性包括ip,端口,密码。再注入。

server:
  port: 8080

# Redis配置
spring:
  redis:
    host: 192.168.200.131
    port: 6379
    password: root
// RedisConfigProperties.java
@Data
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfigProperties {
    private String host;
    private int port;
    private String password;
}

// RedisTemplateConfig.java
@Configuration
public class RedisTemplateConfig {

    @Autowired
    RedisConfigProperties redisConfigProperties;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(
                redisConfigProperties.getHost(), redisConfigProperties.getPort()
        );

        config.setPassword(redisConfigProperties.getPassword());
        return new LettuceConnectionFactory(config);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(){
        RedisTemplate<String,Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory());
        // 设置序列化器等其他配置
        return template;
    }
}

// RedissonConfig.java
@Configuration
@EnableConfigurationProperties({RedisConfigProperties.class})
public class RedissonConfig {

    @Autowired
    RedisConfigProperties redisConfigProperties;

    @Bean
    public RedissonClient redissonClient(){
        // 1. 创建配置文件
        Config config = new Config();

        // 2. 设置单节点服务器配置
        config.useSingleServer().setAddress(
                "redis://"+redisConfigProperties.getHost()+":"+redisConfigProperties.getPort()
        );

        // 3. 如果Redis设置了密码,这里需要设置密码
        config.useSingleServer().setPassword(redisConfigProperties.getPassword());

        // 4. 创建RedissonClient实例
        RedissonClient redisson = Redisson.create(config);

        return redisson;
    }
}

到这里,RedisTemplate和Redisson就已经集成好了,后续使用只需要注入就行。
例如

@RestController
@RequestMapping(value = "/order")
public class OrderController {

    @Autowired
    //private RedisTemplate redisTemplate;
    private StringRedisTemplate redisTemplate; //通常用这个StringRedisTemplate

    @Autowired
    private RedissonClient redissonClient;

	...
	...
}

3. 模拟分布式场景下超卖现象

OrderController

	/***
     * 抢单
     */
    @GetMapping(value = "/v1/{id}/{num}")
    public String addv1(@PathVariable(value = "id")String id,@PathVariable("num")Long num) throws InterruptedException {
        // 1.查询库存
        int count = Integer.valueOf(redisTemplate.opsForValue().get(id));
        System.out.println("剩余库存:"+count);
        // 2.库存充足
        if (count>=num){
            //模拟操作
            TimeUnit.SECONDS.sleep(5);

            //递减库存
            Long decrement = redisTemplate.opsForValue().decrement(id, num);
            System.out.println("递减库存后剩余库存:"+decrement);

            //其它操作 略
            System.out.println("----添加订单了!");

            return "下单成功";

        }
        //库存不足
        else {
            return "库存不足";
        }
    }

复制一个端口为8081的配置,模拟分布式服务

在这里插入图片描述
启动两个服务
在这里插入图片描述
在Redis中设置一个键值对water:2,模拟水的库存为2.
在这里插入图片描述浏览器同时发送2个请求,模拟有2个用户同时每人买2瓶水
http://127.0.0.1:8080/order/v1/water/2
http://127.0.0.1:8081/order/v1/water/2
在这里插入图片描述

出现超卖现象

4. 利用Redisson分布式锁,防止超卖

关键代码

RLock lock = redissonClient.getLock("mylock_" + id);
lock.lock();   //自旋获取锁
...
...
lock.unlock();

首先记得set water 2

OrderController

	/***
     * 抢单,使用分布式锁
     */
    @GetMapping(value = "/{id}/{num}")
    public String add(@PathVariable(value = "id")String id,@PathVariable("num")Long num) throws InterruptedException {
        //对该商品加锁,加锁成功,则判断库存,避免多人同时判断某一个商品的库存
        RLock lock = redissonClient.getLock("mylock_" + id);
        lock.lock();   //自旋获取锁
        System.out.println("获取了锁!"+lock.getName());

        try {
            // 1.查询库存
            int count = Integer.valueOf(redisTemplate.opsForValue().get(id));
            System.out.println("剩余库存:"+count);
            // 2.库存充足
            if (count>=num){
                //模拟操作
                TimeUnit.SECONDS.sleep(5);

                //递减库存
                Long decrement = redisTemplate.opsForValue().decrement(id, num);
                System.out.println("递减库存后剩余库存:"+decrement);

                //其它操作 略
                System.out.println("----添加订单了!");

                return "下单成功";

            }
            //库存不足
            else {
                return "库存不足";
            }
        } finally {
            //释放锁
            System.out.println("释放了锁!"+lock.getName());
            lock.unlock();
        }
    }

启动2个服务,浏览器同时发送2个请求
http://127.0.0.1:8080/order/water/2
http://127.0.0.1:8081/order/water/2
在这里插入图片描述
防止了超卖现象


http://lihuaxi.xjx100.cn/news/2196554.html

相关文章

48、Flink 的 Data Source API 详解

a&#xff09;概述 本节将描述 FLIP-27 中引入的新 Source API 的主要接口。 b&#xff09;Source Source API 是一个工厂模式的接口&#xff0c;用于创建以下组件。 Split EnumeratorSource ReaderSplit SerializerEnumerator Checkpoint Serializer 此外&#xff0c;Sou…

深度解析:短剧市场的发展趋势

一、 短剧视频的兴起 小程序短剧视频是近年来在社交媒体平台上崭露头角的一种内容形式&#xff0c;其独特的表达方式吸引了大量用户的关注&#xff0c;这种类型的视频通常以小幅度、短时长的剧情为主&#xff0c;具有轻松幽默的风格&#xff0c;适合在碎片化的时间作为娱乐消遣…

数据结构之ArrayList与顺序表(上)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 顺序表的学习&#xff0c;点我 上面这篇博文是关于顺序表的基础知识&#xff0c;以及顺序表的实现。…

国标GB/T 28181详解:国标GBT28181-2022的客户端主动发起历史视音频回放流程

目录 一、定义 二、作用 1、提供有效的数据回顾机制 2、增强监控系统的功能性 3、保障数据传输与存储的可靠性 4、实现精细化的操作与控制 5、促进监控系统的集成与发展 三、历史视音频回放的基本要求 四、命令流程 1、流程图 2、流程描述 五、协议接口 1、会话控…

短视频直播教学课程小程序的作用是什么

只要短视频/直播做的好&#xff0c;营收通常都不在话下&#xff0c;近些年&#xff0c;线上自媒体行业热度非常高&#xff0c;每条细分赛道都有着博主/账号&#xff0c;其各种优势条件下也吸引着其他普通人冲入。 然无论老玩家还是新玩家&#xff0c;面对平台不断变化的规则和…

易语言QQ机器人2.0源码

易语言QQ机器人2.0 效果图源码说明领取源码下期更新预报 效果图 源码说明 .程序集 Smessage, VJ_DirectUI .程序集变量 Format, StringFormat.子程序 _初始化, , , 当基于本类的对象被创建后&#xff0c;此方法会被自动调用.子程序 _销毁, , , 当基于本类的对象被销毁前&#x…

持续总结中!2024年面试必问 20 道分布式、微服务面试题(二)

上一篇地址&#xff1a;持续总结中&#xff01;2024年面试必问 20 道分布式、微服务面试题&#xff08;一&#xff09;-CSDN博客 三、CAP定理是什么&#xff1f; CAP定理是分布式系统理论中的一个基本概念&#xff0c;由计算机科学家Eric Brewer在2000年提出&#xff0c;并由…

Java内部类、枚举类、注解类

Java 是一种面向对象的编程语言&#xff0c;它支持多种类型的类&#xff0c;包括内部类、枚举类和注解类 一、内部类&#xff08;Inner Class&#xff09;&#xff1a; 内部类是定义在另一个类内部的类。它可以访问外部类的成员&#xff08;包括私有成员&#xff09;&#xff…