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
在这里插入图片描述
防止了超卖现象

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Redisson实现分布式锁可以确保在分布式环境中对共享资源的访问是互斥的。下面是使用Redisson实现分布式锁的步骤: 1. 添加Redisson依赖:在`pom.xml`文件中添加Redisson依赖。 ```xml <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.15.5</version> </dependency> ``` 2. 配置Redisson连接信息:在`application.properties`文件中配置Redis连接信息。 ```properties spring.redis.host=127.0.0.1 spring.redis.port=6379 ``` 3. 创建RedissonClient Bean:在配置类中创建RedissonClient Bean,用于获取分布式锁实例。 ```java @Configuration public class RedissonConfig { @Value("${spring.redis.host}") private String redisHost; @Value("${spring.redis.port}") private String redisPort; @Bean(destroyMethod = "shutdown") public RedissonClient redissonClient() { Config config = new Config(); config.useSingleServer().setAddress("redis://" + redisHost + ":" + redisPort); return Redisson.create(config); } } ``` 4. 使用分布式锁:在需要进行互斥访问的代码块中使用分布式锁。 ```java @Autowired private RedissonClient redissonClient; public void doSomething() { RLock lock = redissonClient.getLock("myLock"); try { // 尝试获取锁,等待10秒,锁自动释放时间为30秒 boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS); if (isLocked) { // 获得锁之后执行业务逻辑 // ... } else { // 获取锁失败,处理异常情况 // ... } } catch (InterruptedException e) { // 处理异常 // ... } finally { // 释放锁 lock.unlock(); } } ``` 在以上示例中,我们使用Redisson的RLock对象来获取分布式锁使用`tryLock`方法可以尝试获取锁,如果获取成功,则执行相应的业务逻辑;如果获取失败,则根据实际情况处理异常。最后,使用`unlock`方法释放锁。 通过以上步骤,就可以使用Redisson实现分布式锁,确保在分布式环境中对共享资源的互斥访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值