Springboot整合Redission分布式锁使用实例

Springboot整合Redission分布式锁

引言:实际项目中,我们经常会遇到一些需要考虑使用分布式锁的场景,以防止页面重复请求或者多系统之间相互重复调用的产生业务偏差的问题;

例如:

1.并发的场景下,生成订单需要进行使用分布式锁来锁定商品库存,避免出现超卖情况。

2.定时任务,部署多个服务,存在某些任务被同时执行的情况;

一、springboot引入redission依赖;

java 复制代码
        <!-- redis 分布式锁 -->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.5.0</version>
        </dependency>

二、配置redis链接信息:实际各配置信息根据项目具体情况而定

java 复制代码
##默认密码为空
redis:
  host: 127.0.0.1
  port: 6379
  jedis:
    pool:
      #连接池最大连接数(使用负值表示没有限制)
      max-active: 100
      # 连接池中的最小空闲连接
      max-idle: 10
      # 连接池最大阻塞等待时间(使用负值表示没有限制)
      max-wait: 100000
  timeout: 5000
  database: 1

三、RedissonClient客户端配置(单机模式)

java 复制代码
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;

/**
 * 单机模式分布式锁配置
 */

@Configuration
public class RedissionConfig {

    @Value("${redis.host}")
    private String redisHost;

    @Value("${redis.port}")
    private String redisPort;

    @Value("${redis.database}")
    private int database;


    @Bean(destroyMethod = "shutdown")
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer()
                .setAddress("redis://" + redisHost + ":" + redisPort)
                .setDatabase(database);
        return Redisson.create(config);
    }
}

四、测试

4.1 lockTest1方法对锁进行锁定,让现场睡眠1分钟,模拟业务一直占用锁的场景;

4.2 lockTest2 在业务1执行时候尝试去获取锁,看是否能获取到锁,同时等30秒后锁过期再去获取锁,是否可以正常获取到锁;

java 复制代码
	@Resource
    private RedissonClient redissonClient;

    @ApiOperation(value = "分布式可重入锁测试1", notes = "分布式锁测试1")
    @PostMapping("/lockTest1")
    Result lockTest1(@RequestBody RedisRequestDto dto){
        RLock lock = redissonClient.getLock(dto.getKey());
        String message = "";
        try {
            // lock.lock(); 会有看门狗机制,默认30秒;
//            lock.lock();

            // 此处采用手动设置过期时间,不会触发看门狗机制
            boolean locked = lock.tryLock(30, 60, TimeUnit.SECONDS);
            if(locked){
                message = "lockTest1 == 锁成功了";
                log.info(message);
            }else {
                message = "lockTest1 == 1锁失败了";
                log.info(message);
            }
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            if(Objects.nonNull(lock) && lock.isHeldByCurrentThread()){
                log.info("{}锁被释放",dto.getKey());
                lock.unlock();
            }
        }
        return Result.ok(message);
    }

    @ApiOperation(value = "分布式可重入锁测试2", notes = "分布式锁测试2")
    @PostMapping("/lockTest2")
    Result lockTest2(@RequestBody RedisRequestDto dto){
        RLock lock = redissonClient.getLock(dto.getKey());
        try {
            boolean isLocked = lock.isLocked();
            if(isLocked){
                log.info("{}锁被占用,请稍后",dto.getKey());
                return Result.ok("锁占用,请稍后");
            }else {
                log.info("{}锁未占用,继续执行",dto.getKey());
                return Result.ok("锁未占用,继续执行");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(Objects.nonNull(lock) && lock.isHeldByCurrentThread()){
                lock.unlock();
            }
        }
        return Result.ok("");
    }

测试结果:

请求参数如下:

1.lockTest1 执行以后,我们可以看到有在db1中有一条记录,同时返回锁成功;

2.lockTest2 执行时候就是锁占用,证明"test_lock"已经被占用,无法获取;

3.等待30秒以后,test_lock锁自动过期,再次执行lockTest2,可以正常获取到锁;

通过日志,我们也能看出整个锁的锁定和释放的情况;

java 复制代码
2024-01-15 15:15:13.560  INFO 191576 --- [nio-1012-exec-1] c.s.house.controller.RedisController     : lockTest1 == 锁成功了
2024-01-15 15:15:16.960  INFO 191576 --- [nio-1012-exec-3] c.s.house.controller.RedisController     : test_lock锁被占用,请稍后
2024-01-15 15:16:24.566  INFO 191576 --- [nio-1012-exec-5] c.s.house.controller.RedisController     : test_lock锁未占用,继续执行
相关推荐
苹果酱056710 分钟前
一文读懂SpringCLoud
java·开发语言·spring boot·后端·中间件
人生百态,人生如梦17 分钟前
大数据处理从零开始————3.Hadoop伪分布式和分布式搭建
hadoop·分布式
掐指一算乀缺钱30 分钟前
SpringBoot 数据库表结构文档生成
java·数据库·spring boot·后端·spring
晚睡早起₍˄·͈༝·͈˄*₎◞ ̑̑35 分钟前
苍穹外卖学习笔记(七)
java·windows·笔记·学习·mybatis
就这个java爽!41 分钟前
JAVA网络编程【基于TCP和UDP协议】超详细!!!
java·开发语言·网络·tcp/ip·udp·eclipse·idea
一叶飘零_sweeeet1 小时前
为什么 Feign 要用 HTTP 而不是 RPC?
java·网络协议·http·spring cloud·rpc·feign
懒洋洋大魔王1 小时前
7.Java高级编程 多线程
java·开发语言·jvm
芊言芊语1 小时前
分布式缓存服务Redis版解析与配置方式
redis·分布式·缓存
茶馆大橘1 小时前
【黑马点评】已解决java.lang.NullPointerException异常
java·开发语言
星辰@Sea1 小时前
服务注册中心对比及使用场景分析
java·云原生