当前位置: 首页 > article >正文

SpringBoot整合ShedLock,解决定时任务防止重复执行的问题

在分布式系统中,尤其是涉及到定时任务的场景下,任务的重复执行是一个常见问题。例如,多个服务节点同时执行同一个定时任务,可能会导致数据重复处理或者资源争用。ShedLock 是一个解决分布式环境中定时任务重复执行问题的库,它通过使用数据库锁机制确保只有一个节点执行特定的定时任务。

ShedLock 的工作原理
ShedLock 通过对任务加锁来避免多个实例(多个节点)执行同一个定时任务。它依赖于数据库表来存储任务的锁信息。每次执行任务之前,ShedLock 会检查数据库中是否有其他节点已经获得锁。如果没有,它会设置锁并执行任务;如果有,任务会被跳过。

  1. 添加依赖
    在 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>

  1. 创建数据库表
    在使用 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
);

  1. 配置 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 实现的锁提供者
    }
}

  1. 创建定时任务
    接下来,你可以通过 @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:设置任务至少持有锁的时间,防止任务执行过快而过早释放锁。
5. 启用 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);
    }
}

  1. 工作原理
    锁定任务:当定时任务被触发时,ShedLock 会尝试获取锁。如果任务已经有锁,其他节点会跳过该任务的执行。
    分布式锁:通过数据库表,ShedLock 确保分布式环境中多个服务实例不会同时执行相同的任务,避免了重复执行的问题。
    防止任务阻塞:如果任务执行时间过长,ShedLock 会根据配置自动释放锁,防止任务被阻塞。
  2. 其他配置
    你可以通过配置 defaultLockAtMostFor 和 defaultLockAtLeastFor 来全局设置锁的过期时间。defaultLockAtMostFor 表示全局配置的任务最长执行时间,defaultLockAtLeastFor 则表示全局配置的任务最短执行时间。
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M", defaultLockAtLeastFor = "PT30S")

这样,所有使用 @SchedulerLock 注解的任务都将遵循这些全局设置,除非你在注解中显式地覆盖它们。

在 ShedLock 6.2.0 中,集成方式没有太大变化,但提供了更强的配置灵活性和优化。在分布式系统中,ShedLock 可以确保定时任务只会被一个实例执行,有效避免了重复执行的问题。通过数据库存储锁,ShedLock 使得定时任务管理更加可靠,适用于高并发和分布式的应用场景。

通过上述步骤,你可以轻松地在 Spring Boot 项目中使用 ShedLock 来管理定时任务,确保任务不会被重复执行,提升系统的稳定性和性能。


http://www.kler.cn/a/510416.html

相关文章:

  • 信息奥赛一本通 1168:大整数加法
  • 自定义BeanPostProcessor实现自动注入标注了特定注解的Bean
  • 4 AXI USER IP
  • 昇腾环境ppstreuct部署问题记录
  • 动手学大数据-3社区开源实践
  • 微服务入门:从零开始构建你的微服务架构
  • 【2024年华为OD机试】 (B卷,100分)- 敏感字段加密(Java JS PythonC/C++)
  • el-date-picker根据开始时间或结束时间禁用前后时间
  • C# 数据结构全面解析
  • 自动驾驶汽车目前面临的最大技术挑战是什么?
  • linux网络编程11——线程池
  • 【MySQL】事务(二)
  • 二叉树OJ题:挑战与突破
  • springboot自动配置原理(高低版本比较)spring.factories文件的作用
  • RISC-V精简指令集
  • 雷电9最新版安装Magisk+LSPosd(新手速通)
  • 基于SSM的家庭记账本小程序设计与实现(LW+源码+讲解)
  • Git实用指南:忽略文件、命令别名、版本控制、撤销修改与标签管理
  • 国产编辑器EverEdit - 文字对齐
  • Golang学习笔记_27——单例模式
  • S4 HANA凭证更改记录
  • Xilinx FPGA :开发使用及 Tips 总结
  • K8S-Pod资源清单的编写,资源的增删改查,镜像的下载策略
  • 基于无线传感器网络的森林防火设备远程监控系统(论文+源码)
  • 根据进程id查看服务使用的垃圾收集器
  • 论文阅读:CosAE Learnable Fourier Series for Image Restoration