更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍

在 Spring Boot 3 中,整合 Redisson 实现分布式锁可以有效地解决分布式环境下的并发问题。Redisson 是 Redis 官方推荐的客户端,它提供了丰富的分布式对象和高级功能,包括分布式锁的实现。下面介绍如何使用 Spring Boot 3 和 Redisson 来实现分布式锁的功能。

1. 添加 Redisson 依赖

首先,需要在 pom.xml 中添加 Redisson 的依赖,并确保已经引入了 Spring Boot 和 Redis 的相关依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.23.4</version>
        </dependency>

2. 配置 Redisson 客户端

RedissonProperties

application.yml 文件中,配置 Redis 的连接信息,此例以单机版 Redis 为例。config: 后面跟着一个管道符 (|),表示一个多行字符串,也就是一个整体。

spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: redis://localhost:6379    # Redis 连接地址,前缀为 redis://
          password: 			             # 如果 Redis 需要密码认证,则填写密码
          timeout: 3000                      # 命令执行超时时间(毫秒)

如果使用的是 Redis 集群则需要修改为如下配置:

spring:
  redis:
    redisson: 
      config: |
        clusterServersConfig:
          password: 
          nodeAddresses:
          - redis://127.0.0.1:6379
          - redis://127.0.0.2:6379
          - redis://127.0.0.3:6379

接着,在配置类中初始化 Redisson 客户端。

package com.coderjia.boot310redis.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.spring.starter.RedissonProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author CoderJia
 * @create 2024/10/5 下午 04:53
 * @Description
 **/
@Configuration
public class RedissonConfig {

    @Autowired
    private RedissonProperties redissonProperties;

    @Bean
    public RedissonClient redissonClient() throws Exception{
        Config config = Config.fromYAML(redissonProperties.getConfig());
        Redisson.create(config);
        System.out.println("Redisson 已启动");
        return Redisson.create(config);
    }

}

3. 使用 Redisson 实现分布式锁

通过 RedissonClient,我们可以使用分布式锁功能。下面是一个简单的示例,展示如何使用 Redisson 实现分布式锁。

package com.coderjia.boot310redis.service;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @author CoderJia
 * @create 2024/10/5 下午 05:14
 * @Description
 **/
@Service
public class LockService {

    private final RedissonClient redissonClient;

    public LockService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    public void doSomethingWithLock() {
        // 获取锁对象
        RLock lock = redissonClient.getLock("myLock");

        try {
            // 尝试获取锁,等待时间 100ms,锁定时间 10秒
            if (lock.tryLock(100, 10, TimeUnit.SECONDS)) {
                try {
                    // 加锁成功,执行业务逻辑
                    System.out.println("锁定成功,正在执行关键任务...");
                    Thread.sleep(5000);  // 模拟任务执行
                } finally {
                    // 释放锁
                    lock.unlock();
                    System.out.println("任务完成,已释放锁");
                }
            } else {
                System.out.println("无法获取锁,其他线程正在执行该任务");
            }
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }
    }
}

4. 调用分布式锁

在你的业务逻辑中调用上面创建的 LockService 方法。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LockController {

    private final LockService lockService;

    public LockController(LockService lockService) {
        this.lockService = lockService;
    }

    @GetMapping("/test-lock")
    public String testLock() {
        lockService.doSomethingWithLock();
        return "分布式锁测试完成";
    }
}

调用 curl "http://localhost:8080/test-lock?id=A" 接口,进入分布式锁执行逻辑。

单线程情况

开启两个线程,同时调用 curl "http://localhost:8080/test-lock?id=A"curl "http://localhost:8080/test-lock?id=B",可以看到先执行的线程占用了锁,第二个线程要等第一个线程释放锁之后才能重新获得锁。

多线程情况

详细说明

  1. RLock:这是 Redisson 提供的分布式锁对象。通过 RedissonClient.getLock() 方法可以获取到一个分布式锁。

  2. tryLock(long waitTime, long leaseTime, TimeUnit unit):此方法尝试获取锁,其中:

    • waitTime 是最大等待时间,表示在该时间内如果未获取到锁则放弃。
    • leaseTime 是锁的自动释放时间,避免因为业务逻辑异常导致锁无法释放。
  3. unlock():业务逻辑执行完后需要手动释放锁,否则其他线程将无法获取锁。

5. 为什么使用Redisson分布式锁

使用 Redisson 实现的分布式锁相对于直接使用 Redis 的分布式锁,具有一些显著的优势,尤其是在功能完善性、开发便捷性以及可扩展性方面。以下是 Redisson 实现的分布式锁相对于手动实现 Redis 分布式锁的几个主要优势:

优势Redisson 实现分布式锁手动使用 Redis 实现分布式锁
锁机制支持可重入锁、公平锁、读写锁等丰富的锁机制需要手动实现
锁续期机制自动续期,防止锁超时失效需要手动续期
操作原子性内置保证需要 Lua 脚本保障原子性
易用性API 简单,易于使用和维护需要手动编写命令逻辑
部署架构支持支持单点、哨兵、集群模式需要手动处理高可用
高级功能异步、分布式对象、反压支持需要手动封装
异步和同步支持完善的异步和反应式支持需要手动编写异步代码

6. 常见问题

  • 死锁问题:如果业务逻辑执行时间超过锁的自动释放时间,会导致锁自动释放,其他线程可能会获取锁,造成数据不一致问题。为避免这种情况,可以设置足够长的 leaseTime,或者在业务逻辑完成时手动释放锁。

  • 锁竞争激烈:在高并发场景下,多个线程同时竞争锁,可能会导致部分线程长时间无法获取锁。可以通过优化锁的粒度来减少锁的竞争。

7. 总结

通过 Spring Boot 3 和 Redisson 的结合,你可以轻松实现分布式锁的功能,确保在分布式系统中关键任务的正确执行。Redisson 提供了多种锁的实现,如公平锁、读写锁、可重入锁等,能够满足不同的业务需求。

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐