相信大家在JAVA中知道锁的一个概念。在JAVA中,锁是一种机制,用于控制并发代码的执行。锁用于保护共享资源的访问,确保只有一个线程能够同时访问这些资源。锁可以防止多个线程同时执行对共享资源的修改操作,从而避免数据不一致或竞争条件。
但是呢JAVA里面的锁都是基于jvm的。就是说是一个服务独有的。这样的话,在分布式框架中就会有一个问题。比如说我有三个节点。大量的请求进来。我们的需求是不管你请求多少次,只会执行一次。假如说三个节点中每一个节点都进来了一个请求,这样的话就会出现执行了三次请求。这个时候就要请我们的分布式锁出场了。
分布式锁是一种用于在分布式系统中协调多个进程或节点访问共享资源的机制。它可以确保在多个节点上的操作不会发生冲突,避免数据不一致性和竞态条件问题。所以呢我就开发了一个只通过一个注解实现这个功能的工具框架(simple-cache)。
这次V1.4.0主要更新的内容为:
- RedisLock注解实现分布锁
simple-cache-spring-boot-starter
请使用1.4.2
版本
java
<dependency>
<groupId>io.gitee.antopen</groupId>
<artifactId>simple-cache-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
准备条件在博主的上一篇文章上门已经讲的很详细了,这次就不做讲解,只讲新功能
【simple-cache】一款只用一个注解就实现缓存的框架-我们终于迎来了SpringBoot版本
直接在bean类中添加@RedisLock
注解即可。
说明:
@RedisLock可选值
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | string | 是 | 无 | 分布式锁的名称,可以自定义 |
expire | long | 否 | 10L(10秒) | 锁超时时间,锁自动释放 |
unit | TimeUnit | 否 | TimeUnit.SECONDS(一秒) | 时间单位。默认为秒。,可以修改 |
delWhenTaskComplete | boolean | 否 | true | 任务执行完是否释放,可以修改 |
tips | boolean | 否 | 该任务正在执行,请稍后再试 | 有锁时返回的提示,可以修改 |
只有value属性的时候
只有value属性的时候当访问该方法的时候,redis里面会有一个叫testRLock
的锁,默认过期时间为10s
java
@RedisLock(value = "testRLock")
public String testRLock() {
System.out.println("hello testRLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "进入方法了";
}
由于上面我们模拟了这个方法的执行时间为5秒钟,而且我们的delWhenTaskComplete默认值是true,所以没等10秒中过去,任务已经执行完并且自己释放锁了。如果我们在5秒内,也就是说锁还在的时候再次请求这个接口(方法),就会返回tips里面的提示:
expire值
java
@RedisLock(value = "testRLock",expire = 60L)
public String testRLockexpire() {
System.out.println("hello testRLock");
try {
Thread.sleep(500000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "进入方法了";
}
expire值默认是10s,大家可以根据自己项目实际情况去设置秒数,如上是会生成一个60s的锁。
unit值
java
@RedisLock(value = "testRLock", expire = 1L, unit = TimeUnit.HOURS)
public String testRLockexpireAndunit() {
System.out.println("hello testRLock");
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "进入方法了";
}
unit值可以和expire 值结合使用,如上就是会生成一个小时的锁。
delWhenTaskComplete值
java
@RedisLock(value = "testRLock", delWhenTaskComplete = false)
public String testRLockdelWhenTaskComplete() {
System.out.println("hello testRLock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "进入方法了";
}
delWhenTaskComplete默认是true,意思就是不管你锁的过期时间是多少,我任务执行完之后就会释放自己的锁,但是我们可以把他关闭,那么他就不会释放锁了,必须等到锁过期才能自动释放锁。建议大家在设置该值的时候按照实际业务调整和过期时间的设定,建议锁的过期时间要大于业务执行的时间,如果小于执行时间的话,锁就会优先过期掉了。
tips 值
java
@RedisLock(value = "testRLockTips", tips = "别急,等下再试!!")
public String testRLockTips() {
System.out.println("hello testRLock");
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "进入方法了";
}
tips 是提示,大家可以自定义提示,例如上面的别急,等下再试!!
EL表达式
java
/**
* 测试分布式锁
*
* @return string
*/
@GetMapping("/testRLockId")
public Object testRLockId() {
return testRLockService.testRLockId(1);
}
java
@RedisLock(value = "#id")
public String testRLockId(Integer id) {
System.out.println("hello testRLock");
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "进入方法了";
}
同样,这个注解支持EL表达式,只要以#
开头,值和入参名字一样即可,可参考上面的代码实现,上面就是把1作为唯一id作为锁的名称。
完整代码已经开源:
Simple Cache Spring Boot Starter
Simple Cache Spring Boot 快速启动代码
后续版本考虑:
- 添加RedisCount注解,添加计数功能,例如网页访问量
如果有建议欢迎提出
如果你也想为开源贡献自己的力量,欢迎加入蚂蚁开源
使用simple-cache的springboot版本也十分简单,只需要:
- 引入simple-cache-spring-boot-starter依赖;
- 在启动类加上EnableSimpleCache注解;
- 在配置文件中填写属于你自己项目的redistemplate的bean的名称;
- 在你的业务类方法上添加simple-cache的注解。