一、介绍@Ylock
控制多个方法之间的调用关系,帮助解决并发请求修改统一数据造成的数据不一致问题;
二、使用说明
2.1、引入模块
<dependency>
<groupId>me.yyk</groupId>
<artifactId>lock4j</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
如图所示
2.2、配置参数
//注解控制需要扫描的包
ylock.path=me.yyk.*
//引入项目中的 StringRedisTemplate 注入的bean名称
ylock.ylockRedisBeanName=redisCache
//最长上锁时间
ylock.lockTimeout=10
如图所示
注意:
该项目依赖于redis,建议springBoot 版本 2.2.0以上
2.3、在方法上加入注解@YLock
2.3.1、“互斥模式”
@GetMapping("/t")
@YLock(configName = "123",name = "hello")
public String hello(@RequestParam("name") String name) throws InterruptedException {
Thread.sleep(5000);
return "helloMEthod1";
}
@GetMapping("/t1")
@YLock(configName = "123",name = "hello1")
public String hello1(@RequestParam("name") String name) throws InterruptedException {
Thread.sleep(5000);
return "helloMEthod2";
}
分别在hello()和hello1()上加入如上注解,此配置通过configName属性将两个方法纳入到一个锁中管理,得到的效果是:当入参name参数相同时,访问hello() 那么 无法访问hello1()
演示效果:
当我们访问hello()方法,在此方法未执行完成时,访问hello1(),返回如下值
@YLock(configName = "123",name = "hello1",returnInfo = "自定义的返回值")
自定义返回值,定义returnInfo即可
2.3.1、“等待模式”
@GetMapping("/t")
@YLock(configName = "123",name = "hello")
public String hello(@RequestParam("name") String name) throws InterruptedException {
Thread.sleep(3000);
return "helloMEthod";
}
@GetMapping("/t1")
@YLock(configName = "123",name = "hello1",mode = MethodLockUnit.Mode.WAIT,holdTime = 3)
public String hello1(@RequestParam("name") String name) throws InterruptedException {
Thread.sleep(5000);
return "helloMEthod";
}
如上在hello1()方法中配置,mode = MethodLockUnit.Mode.WAIT , holdTime = 3,当hello()在执行时,hello1()方法可以等待holdTime 单位 秒,在重新判断锁的状态,然后发起执行;
2.3.2、"主锁模式"
@GetMapping("/t")
@YLock(configName = "123",name = "hello")
public String hello(@RequestParam("name") String name) throws InterruptedException {
Thread.sleep(3000);
return "helloMEthod";
}
@GetMapping("/t1")
@YLock(configName = "123",name = "hello1",locked = false)
public String hello1(@RequestParam("name") String name) throws InterruptedException {
Thread.sleep(5000);
return "helloMEthod";
}
区别于2.3.1的”互斥模式“,当配置helle1()方法 locked = false,那么程序访问hello1(),是不会上锁的,此时其他请求时可以访问hello()方法,反之则不然,访问hello()方法,会更根据参数上锁;
2.4、提示
2.4.1、自定义加锁的KEY
在实际开发过程中,会遇到需要加锁的方法,没有参数,或者参数不同,是根据参数中的某些值来固定的,此时如何做呢;
本模块提供了自定义key的方法;
@GetMapping("/t2")
@YLock(configName = "123",name = "hello2" )
public String hello2(){
return "helloMEthod";
}
@GetMapping("/t3")
@YLock(configName = "123",name = "hello3")
public String hello3(){
return "helloMEthod";
}
如上图所示为两个没有参数的方法,此时如使用默认”互斥锁定“的配置,那么会抛出异常无法锁定,如下图所示:
模块会发出错误和报警,此时@Ylock注解是不生效的;
那么请新建类,实现 MethodGetKey 的接口方法
/**
* @Classname TestGetKey
* @Description TODO
* @Date 2022/3/30 14:50
* @Created by yuyangkang
*/
public class TestGetKey implements MethodGetKey {
public TestGetKey() {
}
@Override
public String getKey(Object... args) {
return "987678990";
}
}
并将原加锁方法增加参数配置 obtainKey =TestGetKey.class
@GetMapping("/t2")
@YLock(configName = "123",name = "hello2",obtainKey =TestGetKey.class )
public String hello2(){
return "helloMEthod";
}
@GetMapping("/t3")
@YLock(configName = "123",name = "hello3",obtainKey =TestGetKey.class )
public String hello3(){
return "helloMEthod";
}
此两方法即可实现锁定;
同样当两个锁定的方法入参,不相同时那么请各自定义不同的obtainKey的参数,实现返回的key值相同;
源码地址: