Java集成Redisson实现分布式锁(实战)

一、Redisson是什么

Redisson 是一个基于 Redis 实现的 Java 驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列分布式和可扩展的 Java 数据结构,还对 Redis 进行了封装,让开发者可以更便捷地使用 Redis。

二、Redisson作用

  1. 简化 Redis 操作:Redisson 为 Java 开发者提供了一套直观且易于使用的 API,能把 Redis 当作普通的 Java对象或集合来操作,从而减少了与 Redis 交互时的复杂度。例如,你可以像操作 Java 的Map一样操作 Redis 中的哈希表。
  2. 分布式锁和同步机制:Redisson实现了多种分布式锁和同步工具,如可重入锁、公平锁、读写锁等,能确保在分布式环境下多个节点之间的数据一致性和并发控制。
  3. 丰富的数据结构:它提供了分布式的Map、List、Set、Queue等数据结构,这些结构在分布式系统中能被多个节点共享和操作。
  4. 异步和反应式编程支持:Redisson 支持异步和反应式编程模型,可提升应用程序的性能和响应能力。

三、使用场景

  1. 分布式锁:在分布式系统中,多个服务可能会同时访问和修改共享资源,使用 Redisson 的分布式锁可以保证同一时间只有一个服务能够操作该资源,避免数据冲突。例如,在电商系统中,多个订单服务可能同时处理库存扣减的操作,使用分布式锁可以确保库存数据的准确性。
  2. 分布式集合:当需要在多个服务之间共享数据时,可以使用 Redisson的分布式集合。比如,在一个分布式的消息系统中,多个消费者服务可以通过分布式队列来处理消息。
  3. 分布式缓存:利用 Redisson 的分布式Map可以实现分布式缓存,将经常访问的数据存储在 Redis 中,减少数据库的访问压力,提高系统的性能。例如,在一个高并发的 Web 应用中,可以将用户的基本信息缓存在 Redis 中,当用户访问时直接从缓存中获取数据。
  4. 分布式信号量:在分布式系统中,信号量可用于控制对有限资源的访问。例如,在一个分布式的文件上传系统中,可以使用信号量来限制同时上传的文件数量。

四、使用

1、引入依赖:

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>${redisson.version}</version>  <!--版本号根据项目适配-->
</dependency>

3、配置文件

# 数据源配置
spring:
  # redis 配置
  redis:
    # 地址
    host: 127.0.0.1
    # 端口,默认为6379
    port: 6379
    # 数据库索引
    database: 5
    # 密码
    password: 
    # 连接超时时间
    timeout: 60s
    lettuce:
      pool:
        # 连接池中的最小空闲连接
        min-idle: 0
        # 连接池中的最大空闲连接
        max-idle: 8
        # 连接池的最大数据库连接数
        max-active: 8
        # #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms

3、配置类:

@Component
@RefreshScope
public class RedissonConfig {

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

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

    @Value("${spring.redis.password}")
    private String password;

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

    @Bean
    public RedissonClient redissonClient() {
        // 创建配置 指定redis地址及节点信息
        Config config = new Config();
        //单例模式
        config.useSingleServer()
                .setAddress("redis://" + host + ":" + port)
                .setPassword(password) // redis设置了密码,就需设置
                .setDatabase(database);
        // 根据config创建出RedissonClient实例并返回
        return Redisson.create(config);
    }
}

4、工具

@Slf4j
@Component
public class RedissonLock {

    @Resource
    private RedissonClient redissonClient;

    /**
     * lock(), 拿不到lock就不罢休,不然线程就一直block
     */
    public RLock lock(String key) {
        if (StringUtils.isBlank(key)) {
            return null;
        }
        RLock lock = redissonClient.getLock(key);
        try {
            lock = redissonClient.getLock(key);
        } catch (Exception e) {
            log.error("Failed to acquire lock for key: " + key, e);
        }
        return lock;
    }

    /**
     * leaseTime为加锁时间,单位为秒
     * @param key key
     * @param leaseTime 为加锁时间,单位为秒
     */
    public RLock lock(String key, long leaseTime) {
        if (StringUtils.isBlank(key) || leaseTime <= 0) {
            return null;
        }
        RLock lock = redissonClient.getLock(key);
        try {
            lock.lock(leaseTime, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("Failed to acquire lock for key: " + key, e);
        }
        return lock;
    }

    /**
     * timeout为加锁时间,时间单位由unit确定
     */
    public RLock lock(String key, TimeUnit unit, long timeout) {
        if (StringUtils.isBlank(key) || timeout <= 0 || unit == null) {
            return null;
        }
        RLock lock = redissonClient.getLock(key);
        try {
            lock.lock(timeout, unit);
        } catch (Exception e) {
            log.error("Failed to acquire lock for key: " + key, e);
        }
        return lock;
    }

    /**
     * @param lockKey   锁 key
     * @param unit      单位
     * @param waitTime  等待时间
     * @param leaseTime 锁有效时间
     * @return 加锁成功? true:成功 false: 失败
     */
    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("加锁失败: " + e.getMessage());
            return false;
        } catch (Exception e) {
            log.error("加锁过程中发生异常: " + e.getMessage());
            return false;
        }
    }

    /**
     * unlock
     *
     * @param lockKey key
     */
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        if (lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

    /**
     * unlock
     *
     * @param lock 锁
     */
    public void unlock(RLock lock) {
        lock.unlock();
    }
}

5、例子

@RestController
@Slf4j
public class RedissonController {

    @Resource
    private RedissonLock redissonLock;

    @GetMapping("lockTest")
    public void lockTest(String key) {
        try {
            // 加锁
            redissonLock.lock(key);
            System.out.println("获取到锁,开始执行任务");
            // 模拟业务操作
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            redissonLock.unlock(key);
            System.out.println("任务执行完毕,释放锁");
        }
}

总结

Lock和tryLock的区别
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喝汽水的猫^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值