/** * 每5分钟跑一次 */ @Scheduled(cron = "0 */5 * * * ?") public void job1() { log.info("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job1..."); }在分布式环境中容易导致任务重复执行,也许会有人提出使用Quartz,Quartz更适合动态的定时任务。为了解决这一问题,ShedLock提供了一种简单而有效的解决方案,它能够确保在分布式环境下定时任务只被执行一次。
ShedLock是一个轻量级的库,用于防止同一时刻多个节点执行相同的定时任务,它通过在支持的数据库中创建锁来实现这一点,当一个节点获取到锁后,其他节点将无法在同一时间点获取同一个锁,从而避免了任务的重复执行,ShedLock支持多种数据存储,包括但不限于Redis、MongoDB、MySQL等。
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));2.引入依赖:
<!-- 堆代码 duidaima.com --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>4.23.0</version> </dependency> <!--每个外部存储实例所需依赖包不一样,这里是jdbc--> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jdbc-template</artifactId> <version>4.23.0</version> </dependency>3.配置LockProvider:
// 标识该类为配置类 @Configuration //开启定时器 @EnableScheduling // 开启定时任务锁,指定一个默认的锁的时间30秒 @EnableSchedulerLock(defaultLockAtMostFor = "PT30S") public class ShedlockJdbcConfig { /** * 配置锁的提供者 */ @Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider( JdbcTemplateLockProvider.Configuration.builder() .withJdbcTemplate(new JdbcTemplate(dataSource)) .usingDbTime() .build() ); } }4.创建定时任务:
/** * 每1分钟跑一次 * lockAtLeastFor:分布式锁定义的是:每次任务要锁住20秒,20秒是持有锁的最小时间,必须等20秒后才释放锁,并且确保在20秒钟内,该任务不会运行超过1次; * lockAtMostFor:锁最大持有时间30秒,表示最多锁定30秒钟,主要用于防止执行任务的节点挂掉(即使这个节点挂掉,在30秒钟后,锁也被释放),一般将其设置为明显大于任务的最大执行时长;如果任务运行时间超过该值(即任务30秒钟没有执行完),则该任务可能被重复执行。 */ @Scheduled(cron = "0 */1 * * * ?") @SchedulerLock(name = "job1",lockAtLeastFor = "20000", lockAtMostFor = "30000") public void job1() { log.info("time=" + DateTime.now().toString("YYYY-MM-dd HH:mm:ss") + " do job1..."); }相比较于Quartz,ShedLock实现更加简单一些,不需要配置很多及创建多张表。