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

文章要点

  • 自定义配置属性类
  • 集成配置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
在这里插入图片描述
防止了超卖现象

相关推荐

  1. SpringBoot+Redisson分布式

    2024-06-07 22:24:04       45 阅读
  2. SpringBoot+Redisson分布式

    2024-06-07 22:24:04       61 阅读
  3. RedissonRedisTemplate

    2024-06-07 22:24:04       30 阅读
  4. Springboot+分布式Redisson注解封装

    2024-06-07 22:24:04       26 阅读
  5. 如何正确使用Redisson实现分布式

    2024-06-07 22:24:04       27 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-07 22:24:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-07 22:24:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-07 22:24:04       82 阅读
  4. Python语言-面向对象

    2024-06-07 22:24:04       91 阅读

热门阅读

  1. TypeScript 在前端开发中的应用

    2024-06-07 22:24:04       27 阅读
  2. 几何(geometry)

    2024-06-07 22:24:04       26 阅读
  3. 分布式光伏发电的工作原理、特点及优势

    2024-06-07 22:24:04       32 阅读
  4. Flink Watermark详解

    2024-06-07 22:24:04       23 阅读
  5. 大数据与数据科学的学科边界

    2024-06-07 22:24:04       25 阅读
  6. 使用机器学习做医学图像分类的开源项目集锦

    2024-06-07 22:24:04       31 阅读
  7. postgressql——ReadBuffer_common函数(7)

    2024-06-07 22:24:04       27 阅读
  8. MySQL优化器的SQL重写规则

    2024-06-07 22:24:04       30 阅读
  9. 前端js解析websocket推送的gzip压缩json的Blob数据

    2024-06-07 22:24:04       36 阅读