Springboot2.x 使用 Redisson 分布式可重入锁
参考
- https://blog.csdn.net/weixin_43749805/article/details/131399516
- https://github.com/redisson/redisson (官方仓库)
- https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter#spring-boot-starter
- https://github.com/redisson/redisson/wiki/2.-Configuration#262-single-instance-yaml-config-format (官方单机配置案例)
- https://blog.csdn.net/atu1111/article/details/106325258
- https://blog.csdn.net/MissLone/article/details/119569393
- https://zhuanlan.zhihu.com/p/526578310
- https://www.bookstack.cn/read/redisson-doc-cn/distributed_locks.md#81-lock
- https://zhuanlan.zhihu.com/p/264846738
- https://www.cnblogs.com/cxygg/p/15998082.html
- https://www.cnblogs.com/jackson0714/p/redisson.html
- https://www.cnblogs.com/ssskkk/p/16279323.html
- https://blog.csdn.net/qq_43323776/article/details/82939005
注意
- 在单元测试中,测试多线程更新年龄失败,但是并没有抛出错误。 https://blog.csdn.net/MissLone/article/details/119569393
- Redisson 可以作为 Redis 客户端使用,而不仅仅是分布式锁一种使用方式。
- 看门狗的锁默认超时时间为30s,当服务器宕机后,因为锁的有效期是 30 秒,所以会在 30 秒内自动解锁。
- 可以通过给锁设置过期时间,让其自动解锁,则无需手动解锁。
- 红锁。
- 多个实例争抢锁,使用getLock会一直等待锁释放,然后新实例拿到锁再执行。可以使用tryLock设置获取时间,获取不到就会返回 false,但是不会自动续期。
环境
| 环境 | 版本 | 操作 | 
|---|---|---|
| windows | 10 | |
| vs code | 1.84.2 | |
| Spring Boot Extension Pack | v0.2.1 | vscode插件 | 
| Extension Pack for Java | v0.25.15 | vscode插件 | 
| JDK | 11 | |
| Springboot | 2.3.12.RELEASE | |
| mybatis-spring-boot-starter | 2.1.4 | mvn依赖 | 
| redisson-spring-boot-starter | 3.25.0 | mvn依赖 | 
| Apache Maven | 3.8.6 | |
| Redis | 3.0.504 | windows 版本,已停更,建议 linux 中使用 | 
| Apache | 2.4.54 | 包含 abs 压测工具 | 
正文
配置
- 引入 pom.xml依赖。
<dependency>
	<groupId>org.mybatis.spring.boot</groupId>
	<artifactId>mybatis-spring-boot-starter</artifactId>
	<version>2.1.4</version>
</dependency>
- 添加 src\main\resources\application.properties配置,引入redisson 配置文件(单节点与集群配置不一样)。
# 单节点 Redisson 配置
spring.redis.redisson.file=classpath:redisson.yaml
- 创建文件src\main\resources\redisson.yaml并写入配置。
https://github.com/redisson/redisson/wiki/2.-Configuration#262-single-instance-yaml-config-format
singleServerConfig:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
  timeout: 3000
  retryAttempts: 3
  retryInterval: 1500
  password: null
  subscriptionsPerConnection: 5
  clientName: null
  address: "redis://127.0.0.1:6379"
  subscriptionConnectionMinimumIdleSize: 1
  subscriptionConnectionPoolSize: 50
  connectionMinimumIdleSize: 24
  connectionPoolSize: 64
  database: 0
  dnsMonitoringInterval: 5000
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.Kryo5Codec> {}
transportMode: "NIO"
代码
- src\main\java\com\xiaqiuchu\demo\service\StudentService.java
package com.xiaqiuchu.demo.service;
import javax.annotation.Resource;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import com.xiaqiuchu.demo.entity.Student;
import com.xiaqiuchu.demo.mapper.StudentMapper;
@Service
public class StudentService {
    @Resource
    StudentMapper studentMaper;
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 手动管理缓存(基于分布式锁)
     * @param id
     * @return
     */
    public Student toOld(Integer id){
        String lockName = "StudentServiceToOld" + id;
        RLock lock = redissonClient.getLock(lockName);
        try {
            lock.lock();
            System.out.println("获取到锁");
            Student student = studentMaper.findById(id);
            //
            if(Integer.compare(student.getAge(), 100) > 0){
                Assert.isTrue(false, "超过100岁");
            }
            student.setAge((byte) (student.getAge() + 1));
            studentMaper.updateById(student);
            System.out.println("修改成功"+student.getAge());
            return student;
        } finally {
            lock.unlock();
        }
    }
}
- src\main\java\com\xiaqiuchu\demo\controller\StudentController.java
package com.xiaqiuchu.demo.controller;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.xiaqiuchu.demo.service.StudentService;
import org.springframework.web.bind.annotation.GetMapping;
@RestController
@RequestMapping("/student")
public class StudentController {
    
    @Resource
    StudentService studentService;
    
    // http://127.0.0.1:8080/student/toOldByThread
    @GetMapping("toOldByThread")
    public String toOldByThread() {
        ExecutorService executorService = Executors.newFixedThreadPool(6);
        for (int i = 0; i < 110; i++) {
            executorService.execute(()->{
                System.out.println(Thread.currentThread().getName());
                try {
                    studentService.toOld(1);
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
              
            });
        }
        executorService.shutdown();
        return "SUCCESS";
    }
    // http://127.0.0.1:8080/student/toOldByAB
    // ab压测测试 abs -n 110  -c 10 http://127.0.0.1:8080/student/toOldByAB
    @GetMapping("toOldByAB")
    public String toOldByAB() {
        studentService.toOld(1);
        return "SUCCESS";
    }
    
    
}
测试
- ab 压测
abs -n 110  -c 10 http://127.0.0.1:8080/student/toOldByAB
    博  主 :夏秋初
地 址 :https://www.cnblogs.com/xiaqiuchu/p/17914469.html
 
如果对你有帮助,可以点一下 推荐 或者 关注 吗?会让我的分享变得更有动力~
转载时请带上原文链接,谢谢。
    
地 址 :https://www.cnblogs.com/xiaqiuchu/p/17914469.html
如果对你有帮助,可以点一下 推荐 或者 关注 吗?会让我的分享变得更有动力~
转载时请带上原文链接,谢谢。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号