当启动多个定时任务所在服务节点时,会出现同一定时任务重复计算的问题,为了解决这种问题,需要使用分布式定时任务锁,这里讲解的是shedlock,原理是定时任务执行时会先从数据库查看该定时任务是不是在锁的时间内,如果是则不执行。
具体使用的方法如下:
一、引用jar包
<!--分布式定时任务锁-->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>2.2.1</version>
</dependency>
二、创建一个shedlock备用空表,表字段如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iYkV2NhdTN4QzNjR2MlNmYjdTZhljY1gjYhJzMyEmZ18CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
主键name:每个定时任务的一个名字
locked_at:锁的开始时间
lock_until:锁的结束时间
注:创建此表即可,不用填写内容,shedlock会自动把相应的锁表信息add到这张表中
三、增加配置类
package com.gaozhen.webservicedemo.config;
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.TimeZone;
/**
* @descrition shedlock配置类
* @since 2021-07-19 15:19
*/
@Configuration
public class ShedlockConfig {
@Resource
private DataSource dataSource;
/**
* @description CREATE TABLE shedlock (
* NAME VARCHAR ( 64 ) NOT NULL,
* lock_until TIMESTAMP ( 3 ) NOT NULL,
* locked_at TIMESTAMP ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ),
* locked_by VARCHAR ( 255 ) NOT NULL,
* PRIMARY KEY ( NAME )
* );
* @date 2020/6/1 15:19
*/
@Bean
public LockProvider lockProvider() {
return new JdbcTemplateLockProvider(
JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.withTimeZone(TimeZone.getTimeZone("GMT+8"))
.build()
);
}
}
四、启动类增加shedlock注解
package com.gaozhen.webservicedemo;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@MapperScan(value={"com.gaozhen.webservicedemo.mapper"})
@EnableSchedulerLock(defaultLockAtMostFor = "PT20M", defaultLockAtLeastFor = "PT20M")
public class WebservicedemoApplication {
public static void main(String[] args) {
SpringApplication.run(WebservicedemoApplication.class, args);
}
}
PT20M 代表20分钟
五、定时任务增加shedlock注解
package com.gaozhen.webservicedemo.task;
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class CronTest {
@Scheduled(cron = "0/5 * * * * ?")
@SchedulerLock(name = "gztest", lockAtLeastFor = 2000, lockAtMostFor = 3000)
public void tastTest(){
System.out.println(new Date());
}
}
lockAtMostFor:锁的最大时间单位为毫秒
lockAtLeastFor:锁的最小时间单位为毫秒
比如你的定时任务执行时间是每5秒执行一次,则需要配置的锁时间就不能超过5秒,最好为2-3秒。这样既能防止同一时间重复执行,又能避免锁耽误正常定时任务的执行。
六、同时启动8500、8501两个服务测试结果如下:
就不会同一时间重复运行的问题了。