SpringBoot与Redisson整合,用注解方式解决分布式锁的使用问题

文章引用:https://mp.weixin.qq.com/s/XgdKE2rBKL0-nFk2NJPuyg

一、单个服务

1.代码

该接口的作用是累加一个值,访问一次该值加1

java 复制代码
@RestController
public class LockController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/increment")
    public String increment() {
        int counter = Integer.parseInt(stringRedisTemplate.opsForValue().get("count"));
        counter++;
        System.out.println("当前结果:" + counter);
        stringRedisTemplate.opsForValue().set("count", String.valueOf(counter));
        return "结果:" + counter;
    }
}

2.jmeter工具压测

用100个线程,每个线程访问100次去压测,理论上该值最后应该返回10000

3.结果


发生了线程安全问题,部分请求返回结果相同

4.解决办法:加锁

java 复制代码
@RestController
public class LockController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/increment")
    public synchronized String increment() {
        int counter = Integer.parseInt(stringRedisTemplate.opsForValue().get("count"));
        counter++;
        System.out.println("当前结果:" + counter);
        stringRedisTemplate.opsForValue().set("count", String.valueOf(counter));
        return "结果:" + counter;
    }
}

在非集群模式下,简单上锁能解决线程安全问题。

二、集群模式

代码相同,idea启动两个相同的服务

1.启动两个服务

2.nginx配置负载均衡

xml 复制代码
upstream backend {
        # 定义后端服务器列表
        server localhost:8081;
        server localhost:8082;
    }
	
	server {
        listen 8080;

        location / {
            # 将请求代理到后端服务器
            proxy_pass http://backend;
        }
    }

3.jmeter工具压测

用100个线程,每个线程访问100次去压测,理论上该值最后应该返回10000

还是出了线程安全问题,synchronized只能锁住单个服务

三、SpringBoot整合Redisson(注解方式)

1.依赖和配置文件

xml 复制代码
<dependencies>
        <!-- Spring Boot Starter for Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--         Redisson Dependency-->
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.17.6</version><!-- 请根据需要调整版本 -->
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>
    </dependencies>
yaml 复制代码
spring:
redis:
  host:localhost
  port:6379

# Redisson configuration
redisson:
  single-server-address:redis://@localhost:6379

2.代码

注解

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributedLock {
    String lockName();
}

切面

java 复制代码
@Aspect
@Component
public class DistributedLockAspect {

    @Autowired
    private RedissonClient redissonClient;

    @Around("@annotation(DistributedLock)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        DistributedLock annotation = signature.getMethod().getAnnotation(DistributedLock.class);
        String lockName = annotation.lockName();

        RLock lock = redissonClient.getLock(lockName);

        try {
            // 尝试获取锁,最多等待10秒,持有锁的时间为30秒
            if (!lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                throw new RuntimeException("Failed to acquire lock.");
            }

            return joinPoint.proceed();
        } finally {
            // 确保在任何情况下都能释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}

接口

java 复制代码
@RestController
public class LockController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/increment")
    @DistributedLock(lockName = "counterLock")
    public String increment() {
        int counter = Integer.parseInt(stringRedisTemplate.opsForValue().get("count"));
        counter++;
        System.out.println("当前结果:" + counter);
        stringRedisTemplate.opsForValue().set("count", String.valueOf(counter));
        return "结果:" + counter;
    }
}

3.结果

实现了分布式锁,俩个服务依次接受了所有请求,并无重复值

相关推荐
ym hyd 1112 小时前
试题库管理系统源码 Java+SpringBoot+Vue3 前后分离
java·vue.js·spring boot·毕设
步行cgn4 小时前
Spring 全注解开发详解
java·后端·spring
IT_陈寒7 小时前
SpringBoot启动慢得像蜗牛?原来是这个配置在捣鬼
前端·人工智能·后端
mftang8 小时前
EtherCAT协议:从“飞读飞写”机制到分布式时钟同步的实时以太网架构深度解析
分布式·架构·ethercat·分布式时钟·从站控制器
不才不才不不才9 小时前
Spring 源码系列(29): 20 道高频面试题源码级解析合集
java·后端·spring
索隆zoro9 小时前
Army 的可插拔架构:army-jdbc 与方言模块
java·后端
小蒜学长10 小时前
校园社团招新网站的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端·校园社团招新网站
蜗牛互联网11 小时前
从Barclays扩大Claude部署看受监管软件工程的责任重分配
java·大数据·人工智能·后端·软件工程
卓怡学长12 小时前
w192基于springboot“考研情报站”微信小程序设计与实现
java·spring boot·spring·微信小程序·intellij-idea
ShineWinsu12 小时前
对于Redis:Hash类型的解析
c++·redis·分布式·缓存·面试·hash·哈希表