SpringBoot使用Redisson实现分布式锁

SpringBoot使用Redisson实现分布式锁

一、前言

1.Redisson

Redisson是Redis官方推荐的Java版的Redis客户端(Jedis、letture也是官方推荐的java版本redis客户端程序)。它提供的功能非常多,也非常强大,特别是它默认提供的分布式锁支持功能。

2.准备工作

数据库信息:
在这里插入图片描述
t_product商品信息:
在这里插入图片描述

二、Spring Boot 集成Redisson

1.添加依赖

redisson相关依赖:

<!--spring data redis启动器-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
    <version>1.4.2.RELEASE</version>
</dependency>
<!--redisson-->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.19.3</version>
</dependency>

其他依赖如下:

<!--tk.mybatis依赖-->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>1.2.4</version>
</dependency>

<!--web依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.32</version>
</dependency>

<!--数据库连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.16</version>
</dependency>

2.配置redis信息

# 服务端口
server:
 port: 8083

## Redisson 分布式锁配置
redisson:
 address: redis://localhost:6379
 password:

3.编写Redisson配置类

package com.example.distributedlockdemo.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * redisson配置类
 * @author qzz
 * @date 2023/3/10
 */
@Configuration
public class RedissonAutoConfiguration {
    
    

    /**
     * redis 链接地址
     */
    @Value("${redisson.address}")
    private String addressUrl;

    /**
     * 密码
     */
    @Value("${redisson.password}")
    private String password;

    /**
     * 单机模式配置
     * @return
     */
    @Bean
    public RedissonClient getRedisson(){
    
    
        Config config = new Config();
        //单机模式
        config.useSingleServer()
                .setAddress(addressUrl).setPassword(password)
                .setRetryInterval(5000)
                .setTimeout(10000)
                .setConnectTimeout(10000);
        return Redisson.create(config);
    }

    /**
     * 主从模式配置
     * @return
     */
//    @Bean
//    public RedissonClient getRedisson(){
    
    
//        Config config = new Config();
//        //主从模式
//        config.useMasterSlaveServers()
//                .setMasterAddress("redis://***(主服务器IP):6379").setPassword(password)
//                .addSlaveAddress("redis://***(从服务器IP):6379")
//                .setRetryInterval(5000)
//                .setTimeout(10000)
//                //连接超时,单位:毫秒 默认值:3000
//                .setConnectTimeout(10000);
//        return Redisson.create(config);
//    }

    /**
     * 哨兵模式配置
     * @return
     */
//    @Bean
//    public RedissonClient getRedisson(){
    
    
//        Config config = new Config();
//        //哨兵模式
//        config.useSentinelServers()
//                .setMasterName("myMaster").setPassword(password)
//                .addSentinelAddress("***(哨兵IP):26379","***(哨兵IP):26379");
//        return Redisson.create(config);
//    }
}

4.编写下单接口(秒杀接口)

package com.example.distributedlockdemo.controller;

import com.example.distributedlockdemo.dao.OrderMapper;
import com.example.distributedlockdemo.dao.ProductMapper;
import com.example.distributedlockdemo.entity.Order;
import com.example.distributedlockdemo.entity.Product;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;


/**
 * @author qzz
 * @date 2023/3/10
 */
@RestController
public class TestController {
    
    

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 下单,减库存
     * @param order
     * @return
     */
    @PostMapping("/order/add")
    public String createOrderTest(@RequestBody Order order){
    
    
        //1.判断库存
        if(!decProductStore(order.getProductId(),order.getProductNum())){
    
    
            return "库存不足!";
        }
        //2.商品下单
        //订单状态 0:未支付 1:已支付 2:已发货 3:已取消
        order.setStatus(0);
        order.setCreateTime(new Date());
        Integer result = orderMapper.insert(order);
        if(result>0){
    
    
            //3.减商品库存
            productMapper.updateProductStock(order.getProductId(),order.getProductNum());
        }
        return "下单成功";
    }

    /**
     * 判断库存
     * @param productId 商品id
     * @param productNum 购买数量
     * @return
     */
    public boolean decProductStore(Long productId, Integer productNum){
    
    
        String key="decrease_stock_lock:" + productId;
        RLock lock = redissonClient.getLock(key);
        //1.加锁
        lock.lock();
        try {
    
    //2.执行业务
            //根据商品id和购买数量判断商品剩余库存
            Product product = productMapper.selectByPrimaryKey(productId);
            //如果库存为空或库存不足
            if (product.getStock() == 0 || product.getStock()-productNum <0) {
    
    
                return false;
            }
        }catch (Exception e){
    
    
            System.out.println(e.getMessage());
        }finally {
    
    
            //解锁
            lock.unlock();
        }
        return true;
    }
}

5.测试

执行一次:购买数量100
在这里插入图片描述

商品库存:
在这里插入图片描述
执行一次:购买数量1
在这里插入图片描述

在这里插入图片描述

数据库中的商品已经全部被秒杀完 并未出现超库存的情况。

猜你喜欢

转载自blog.csdn.net/qq_26383975/article/details/129487761