通过@SchedulerLock使集群环境下同一定时任务只执行一次的简单示例
在一些业务场景下,我们只希望他执行一次,此时可通过@SchedulerLock来对该定时任务进行加锁从而控制定时任务执行次数(也可通过Redis实现分布式锁,本文不做拓展)。,若属性lockAtLeastFor时间大于CRON表达式所表示的任务执行时间间隔,则任务实际执行时间间隔是lockAtLeastFor的值(对应此处的定时任务,会20s输出一次而不是5s)。ShedLock使用外部存储,如M
·
@SchedulerLock简单示例
背景
在分布式多机集群环境下,一个服务可能有多个实例,其中的定时任务@Scheduled也会多次触发。在一些业务场景下,我们只希望他执行一次,此时可通过@SchedulerLock来对该定时任务进行加锁从而控制定时任务执行次数(也可通过Redis实现分布式锁,本文不做拓展)。
引入@SchedulerLock相关依赖
<!--shedlock-->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>4.42.0</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>4.42.0</version>
</dependency>
ShedLock使用外部存储,如Mongo,JDBC,Redis,Hazelcast,ZooKeeper等,本文采用JDBC。
创建shedlock表
CREATE TABLE `shedlock` (
`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`lock_until` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`locked_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`locked_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
添加LockProvider配置:ShedLockConfig
package com.ergo.demo.config;
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
@Component
public class ShedLockConfig {
@Bean
private LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}
配置数据源及数据库连接信息
引入JDBC、MySQL依赖
<!--mysql jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
引入Druid数据源依赖
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.23</version>
</dependency>
application.properties
server.port=8081
spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/data-center?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.async-init=true
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-active=50
spring.datasource.druid.max-wait=6000
spring.datasource.druid.pool-prepared-statements=false
spring.datasource.druid.max-open-prepared-statements=20
spring.datasource.druid.validation-query=select 1
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=300000
spring.datasource.druid.max-evictable-idle-time-millis=172800000
spring.datasource.druid.keep-alive=true
spring.datasource.druid.time-between-log-stats-millis=86400000
spring.datasource.druid.filter.stat.enabled=true
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=3000
创建定时任务
package com.ergo.demo.schedule;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ergo
* @date 2023/3/31 14:43
* @description 定时任务测试
*/
@Component
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class TestSchedule {
@Scheduled(cron = "0/5 * * * * ? ") // 5秒执行一次
@SchedulerLock(name = "test",lockAtLeastFor = "20000",lockAtMostFor = "30000")
public void test() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date()));
}
}
注解 | 含义 |
---|---|
@EnableScheduling | 开启定时任务 |
@EnableSchedulerLock | 开启定时任务锁,defaultLockAtMostFor属性表示默认最大锁持有时间,PT30S表示30秒。 |
@SchedulerLock
放在需要加锁的定时任务上
属性 | 含义 |
---|---|
name | 锁名称 |
lockAtLeastFor | 任务节点锁的最短占有时间,此处为20s |
lockAtMostFor | 任务节点锁的最长占有时间,此处为30s |
特别地,若属性lockAtLeastFor时间大于CRON表达式所表示的任务执行时间间隔,则任务实际执行时间间隔是lockAtLeastFor的值(对应此处的定时任务,会20s输出一次而不是5s)。
测试结果
idea启动多个节点
启动节点观察结果
更多推荐
所有评论(0)