Springboot定时任务集成shedLock锁
0、写在前面
最近在项目开发过程中,涉及到定时任务的编写,定时任务大家都知道,在多服务器部署时,为了防止同一时间同一任务多次执行的问题,通常需要使用分布式定时任务进行处理,这部分对应的框架也很多,例如:xxl-job,power-job,elastic-job,但是由于考虑到当前所负责开发的项目体量,感觉使用上面所提到的分布式定时任务框架太过于繁重,所以,这里就使用了spring提供的scheduler定时任务注解方式开发,虽然此种方式开发简便,但是同一时间同一任务多次执行的问题还是存在的,因此为了解决此问题,这里便引入了shedlock锁组件。
关于shedlock,这里机翻了官网的一段说明,仅供简单介绍,详细可参看官网介绍(官网地址:https://github.com/lukas-krecan/ShedLock
1、版本说明
Spring Cloud Alibaba版本:2022.0.0.0-RC1
Springboot版本:3.0.0
jdk版本:17.0.6
ShedLock版本:5.3.0
mysql版本:8.0.30
2、ShedLock使用
由于项目使用的数据库为MySQL数据库,所以这里使用了shedlock-jdbcTemplate方式,关于其他存储方式的使用可以参看官网(官网地址:https://github.com/lukas-krecan/ShedLock)
2.1、创建数据库
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL COMMENT '锁名称',
lock_until TIMESTAMP(3) NOT NULL COMMENT '释放锁时间',
locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '获取锁时间',
locked_by VARCHAR(255) NOT NULL COMMENT '锁提供者',
PRIMARY KEY (name)
);
官网说明:
<properties>
<shedlock.version>5.3.0</shedlock.version>
</properties>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-core</artifactId>
<version>${shedlock.version}</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>${shedlock.version}</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>${shedlock.version}</version>
<exclusions>
<exclusion>
<artifactId>spring-jdbc</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.0.6</version>
</dependency>
说明:
由于Springboot 3.0.0版本使用的Spring 6.0.2版本在针对数据表中存在数据插入时,会报Duplicate key violation gets translated to DataIntegrityViolationException instead of DuplicateKeyException异常(issue地址:https://github.com/spring-projects/spring-framework/issues/29511),导致shedlock执行时,报类似异常,针对此问题,spring官方也进行了修复(https://github.com/spring-projects/spring-framework/releases/tag/v6.0.3),但是由于项目依赖管理的父pom定义了spring的版本,这里不方便修改父pom的依赖信息,所以就在项目中单独添加了spring-jdbc的依赖,已解决此异常。异常信息如下:
Spring官方修复信息:
@Configuration
public class SchedulerLockConfig {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(
JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.build()
);
}
}
2.4、启动类配置
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
...
@Scheduled(cron = "0 */2 * * * ?")
@SchedulerLock(name = "scheduledTaskName", lockAtLeastFor = "PT60S", lockAtMostFor = "PT60S")
@Transactional(rollbackFor = Exception.class)
public void scheduledTask() {
// 代码省略......
}
shedlock数据表数据:
2.6、注解说明
@SchedulerLock:
关于lockAtLeastFor、lockAtMostFor属性说明:
当第一个微服务执行定时任务的时候,会将此定时任务进行锁操作,然后其他的定时任务就不会再执行,锁操作有一定的时长,超过这个时长以后,锁释放,然后所有的定时任务进行争抢下一个定时任务的执行权利,如此循环。其中两个配置lockAtMostFor和lockAtLeastFor,保证了在一个定时任务的区间内只有一个定时任务在执行,同时也保证了即便是其中的一个定时任务挂掉了,到一定的时间以后,锁也会释放,其他的定时任务依旧会进行执行权的争夺,执行定时任务。