Spring Boot 集成Redisson实现分布式锁

分布式锁实现

引入jar包

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.13.6</version> </dependency> 

说明:关于集成Redisson,我们需要注意与Spring Boot的版本对应。具体对应的关系如下:


注意:3.13.6对应的Spring Boot的版本为2.3.0,而redis-spring-data为redis-spring-data-23。我们可以通过查看pom文件的引用从而得到依赖关系。

Redisson的配置

application.yml中引入redisson.yml配置

redis: redisson: file: classpath:redisson.yml 

redisson.yml配置

singleServerConfig:
  password: xxxx
  address: "redis://127.0.0.1:6379" database: 1
threads: 0
nettyThreads: 0
codec: !<org.redisson.codec.FstCodec> {}
transportMode: "NIO" 

说明:本文配置的是单机环境,如果需要配置集群环境,可以采用如下配置:

clusterServersConfig:
          idleConnectionTimeout: 10000 connectTimeout: 10000 timeout: 3000 retryAttempts: 3 retryInterval: 1500 failedSlaveReconnectionInterval: 3000 failedSlaveCheckInterval: 60000 password: null subscriptionsPerConnection: 5 clientName: null loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> {}
          subscriptionConnectionMinimumIdleSize: 1 subscriptionConnectionPoolSize: 50 slaveConnectionMinimumIdleSize: 24 slaveConnectionPoolSize: 64 masterConnectionMinimumIdleSize: 24 masterConnectionPoolSize: 64 readMode: "SLAVE" subscriptionMode: "SLAVE" nodeAddresses:
          - "redis://127.0.0.1:6379" - "redis://127.0.0.1:6380" - "redis://127.0.0.1:6381" scanInterval: 1000 pingConnectionInterval: 0 keepAlive: false tcpNoDelay: false threads: 6 nettyThreads: 12 codec: !<org.redisson.codec.MarshallingCodec> {}
        transportMode: "NIO" 

封装Redisson工具类

@Component public class RedissonLockUtil { private static final Logger logger = LoggerFactory.getLogger(RedissonLockUtil.class); @Autowired private RedissonClient redissonClient; /**
         * 加锁
         * @param lockKey
         * @return */ public RLock lock(String lockKey) {
            RLock lock = redissonClient.getLock(lockKey); return lock;
        } /**
         * 公平锁
         * @param key
         * @return */ public RLock fairLock(String key) { return redissonClient.getFairLock(key);
        } /**
         * 带超时的锁
         * @param lockKey
         * @param timeout 超时时间 单位:秒
         */ public RLock lock(String lockKey, int timeout) {
            RLock lock = redissonClient.getLock(lockKey);
            lock.lock(timeout, TimeUnit.SECONDS); return lock;
        } /**
         * 读写锁
         * @param key
         * @return */ public RReadWriteLock readWriteLock(String key) { return redissonClient.getReadWriteLock(key);
        } /**
         * 带超时的锁
         * @param lockKey
         * @param unit 时间单位
         * @param timeout 超时时间
         */ public RLock lock(String lockKey, TimeUnit unit ,int timeout) {
            RLock lock = redissonClient.getLock(lockKey);
            lock.lock(timeout, unit); return lock;
        } /**
         * 加锁
         * @param key
         * @param supplier
         * @return */ public <T> T lock(String key, Supplier<T> supplier) {
            RLock lock = lock(key); try {
                lock.lock(); return supplier.get();
            } finally { if (lock != null && lock.isLocked()) {
                    lock.unlock();
                }
            }
        } /**
         * 尝试获取锁
         * @param lockKey
         * @param waitTime 等待时间
         * @param leaseTime 自动释放锁时间
         * @return */ public boolean tryLock(String lockKey, int waitTime, int leaseTime) {
            RLock lock = redissonClient.getLock(lockKey); try { return lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
            } catch (InterruptedException e) { return false;
            }
        } /**
         * 尝试获取锁
         * @param lockKey
         * @param unit 时间单位
         * @param waitTime 等待时间
         * @param leaseTime 自动释放锁时间
         * @return */ public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
            RLock lock = redissonClient.getLock(lockKey); try { return lock.tryLock(waitTime, leaseTime, unit);
            } catch (InterruptedException e) { return false;
            }
        } /**
         * 释放锁
         * @param lockKey
         */ public void unlock(String lockKey) {
            RLock lock = redissonClient.getLock(lockKey);
            lock.unlock();
        } /**
         * 释放锁
         * @param lock
         */ public void unlock(RLock lock) {
            lock.unlock();
        }
    }

模拟秒杀扣减库存

public int lockStock() {
        String lockKey="lock:stock";
        String clientId = UUID.randomUUID().toString(); //加锁 RLock lock=redissonLockUtil.lock(lockKey);
        lock.lock(); try {
           logger.info("加锁成功 clientId:{}",clientId); int stockNum= Integer.valueOf((String)redisUtil.get("seckill:goods:stock")); if(stockNum>0)
           {   
              stockNum--;
              redisUtil.set("seckill:goods:stock",String.valueOf(stockNum));
              logger.info("秒杀成功,剩余库存:{}",stockNum);
           } else {
              logger.error("秒杀失败,剩余库存:{}", stockNum);
           } //获取库存数量 return stockNum;
        } catch (Exception e)
        {
           logger.error("decry stock eror",e);
        } finally { if(lock!=null)
            {
                lock.unlock(); 
            }
        } return 0;
    }

测试代码

@RequestMapping("/redisLockTest") public void redisLockTest() { // 初始化秒杀库存数量 redisUtil.set("seckill:goods:stock", "10");

        List<Future> futureList = new ArrayList<>(); //多线程异步执行 ExecutorService executors = Executors.newScheduledThreadPool(10); // for (int i = 0; i < 30; i++)
        {
            futureList.add(executors.submit(this::lockStock)); try {
               Thread.sleep(100);
            } catch (InterruptedException e) 
            {
               logger.error("redisLockTest error",e);
            }
        } // 等待结果,防止主线程退出 futureList.forEach(t -> { try { int stockNum =(int) t.get();
                logger.info("库存剩余数量:{}",stockNum);
            } catch (Exception e)
            {
               logger.error("get stock num error",e);
            }
        });
    }

执行结果如下:


总结

本文针对Spring Boot集成Redisson的基本使用。

#java#
全部评论
最近正在学这个,感谢分享
点赞 回复 分享
发布于 2022-08-25 18:50 陕西

相关推荐

头像
11-09 12:17
清华大学 C++
out11Man:小丑罢了,不用理会
点赞 评论 收藏
分享
点赞 1 评论
分享
牛客网
牛客企业服务