SpringBoot整合ShedLock解决定时任务防止重复执行的问题
作者:❀͜͡傀儡师
在分布式系统中,尤其是涉及到定时任务的场景下,任务的重复执行是一个常见问题。例如,多个服务节点同时执行同一个定时任务,可能会导致数据重复处理或者资源争用。ShedLock 是一个解决分布式环境中定时任务重复执行问题的库,它通过使用数据库锁机制确保只有一个节点执行特定的定时任务。
ShedLock 的工作原理
ShedLock 通过对任务加锁来避免多个实例(多个节点)执行同一个定时任务。它依赖于数据库表来存储任务的锁信息。每次执行任务之前,ShedLock 会检查数据库中是否有其他节点已经获得锁。如果没有,它会设置锁并执行任务;如果有,任务会被跳过。
添加依赖
在 Spring Boot 项目中集成 ShedLock,需要在 pom.xml 中添加相关依赖。
<dependencies> <!-- ShedLock核心库 --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>6.2.0</version> <!-- 最新版本 --> </dependency> <!-- ShedLock数据库存储实现(JPA) --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jpa</artifactId> <version>6.2.0</version> <!-- 最新版本 --> </dependency> <!-- Spring Boot JPA 支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 选择合适的数据库,例如 H2 或 MySQL --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies>
创建数据库表
在使用 ShedLock 时,需要创建一个数据库表来存储锁的状态。以下是示例的 SQL 脚本,适用于 MySQL 或其他关系型数据库。
CREATE TABLE shedlock ( name VARCHAR(64) PRIMARY KEY, lock_until TIMESTAMP NOT NULL, locked_at TIMESTAMP NOT NULL, locked_by VARCHAR(255) NOT NULL );
配置 ShedLock 数据源
然后,在 Spring Boot 配置类中启用 ShedLock,配置数据库存储和锁提供者。
配置类 ShedLockConfig.java:
import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jparepository.JpaLockProvider; import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import javax.persistence.EntityManager; import javax.sql.DataSource; @Configuration @EnableSchedulerLock(defaultLockAtMostFor = "PT30M") // 默认任务最长执行时间 30 分钟 @EnableJpaRepositories("net.javacrumbs.shedlock.provider.jparepository") // 启用 JPA 存储库 public class ShedLockConfig { @Bean public LockProvider lockProvider(EntityManager entityManager) { return new JpaLockProvider(entityManager); // 使用 JPA 实现的锁提供者 } }
创建定时任务
接下来,你可以通过 @Scheduled 注解定义定时任务,并使用 @SchedulerLock 注解来确保任务不会在多个节点上同时执行。
示例:定时任务 ScheduledTasks.java:
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class ScheduledTasks { // 每分钟执行一次任务,使用 ShedLock 确保任务不会被重复执行 @Scheduled(cron = "0 * * * * ?") @SchedulerLock(name = "exampleTask", lockAtMostFor = "PT30S", lockAtLeastFor = "PT30S") public void exampleTask() { System.out.println("Executing example task..."); // 任务逻辑,例如更新数据、发送通知等 } }
在上述代码中,@SchedulerLock 注解通过 name 参数来标识任务名称,确保相同名称的任务只会由一个节点执行。lockAtMostFor 和 lockAtLeastFor 分别表示任务最多和最少保持锁定的时间,防止任务执行时间过短或过长。
- lockAtMostFor:设置任务执行时,最多持有锁的时间。如果任务执行时间超过该时间,锁将被释放。
- lockAtLeastFor:设置任务至少持有锁的时间,防止任务执行过快而过早释放锁。
启用 Spring Boot 定时任务功能
确保启用了 Spring Boot 的定时任务功能。你可以在 application.properties 或 application.yml 中配置相关属性,或者在启动类中启用 @EnableScheduling。
application.properties 配置:
spring.scheduling.enabled=true
或者在主启动类上使用 @EnableScheduling 注解启用定时任务:
主启动类 SpringBootApplication.java:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class SpringBootApplication { public static void main(String[] args) { SpringApplication.run(SpringBootApplication.class, args); } }
工作原理
锁定任务:当定时任务被触发时,ShedLock 会尝试获取锁。如果任务已经有锁,其他节点会跳过该任务的执行。
分布式锁:通过数据库表,ShedLock 确保分布式环境中多个服务实例不会同时执行相同的任务,避免了重复执行的问题。
防止任务阻塞:如果任务执行时间过长,ShedLock 会根据配置自动释放锁,防止任务被阻塞。
其他配置
你可以通过配置 defaultLockAtMostFor 和 defaultLockAtLeastFor 来全局设置锁的过期时间。defaultLockAtMostFor 表示全局配置的任务最长执行时间,defaultLockAtLeastFor 则表示全局配置的任务最短执行时间。
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M", defaultLockAtLeastFor = "PT30S")
这样,所有使用 @SchedulerLock 注解的任务都将遵循这些全局设置,除非你在注解中显式地覆盖它们。
在 ShedLock 6.2.0 中,集成方式没有太大变化,但提供了更强的配置灵活性和优化。在分布式系统中,ShedLock 可以确保定时任务只会被一个实例执行,有效避免了重复执行的问题。通过数据库存储锁,ShedLock 使得定时任务管理更加可靠,适用于高并发和分布式的应用场景。
通过上述步骤,你可以轻松地在 Spring Boot 项目中使用 ShedLock 来管理定时任务,确保任务不会被重复执行,提升系统的稳定性和性能。
到此这篇关于SpringBoot整合ShedLock解决定时任务防止重复执行的问题的文章就介绍到这了,更多相关SpringBoot ShedLock防止重复执行内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!