Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

本文主要是介绍Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行...

前言

在分布式系统中,定时任务的执行往往需要考虑到多个实例的并发执行问题。假设一个定时任务会在多个节点上并发执行,可能导致重复执行,甚至引发数据异常或系统不一致问题。为了解决这一问题,ShedLock 是一个简单而有效的解决方案,它可以确保在分布式环境中,只有一个节点在某一时刻执行指定的定时任务。

什么是 ShedLock?

ShedLock 是一个轻量级的 Java 库,用于解决分布式系统中定时任务的重复执行问题。它的核心思想是在数据库中加锁,确保在分布式环境下,只有一个节点能够在指定时间执行某个任务。ShedLock 可以与 Spring SchedulerQuartz 等定时任务框架结合使用。

github开源地址:https://github.com/lukas-krecan/ShedLock 目前拥有 3.7K Star,小伙伴们也可以针对文档更系统性的学习如何应用ShedLock。

ShedLock 的工作原理:

❶ 定时任务执行时,ShedLock 会尝试在数据库中为该任务获取锁。
❷ 如果当前节点成功获取到锁,则执行定时任务。
❸ 如果当前节点未能获取到锁(其他节点已获取锁),则该任务跳过执行,等待下次调度。

定时任务重复执行的问题

在分布式应用中,定时任务往往通过多个实例运行,每个实例都会按照自己的调度计划执行任务。例如,假设有一个定时任务负责同步某个外部系统的数据。如果该任务在多个实例上同时执行,就会导致重复的数据同步,进而造成数据不一致、重复处理等问题。

典型场景
我们来模拟一个场景,假设在一个电商系统中,定时任务负责将库存数据同步到第三方库存管理系统。如果该任务在多个节点上同时执行,可能会导致:

1、重复的库存更新请求。
2、数据不同步或数据丢失。
3、系统负载过高,造成性能瓶颈。

使用 ShedLock 解决定时任务重复执行问题

接下来,博主将通过 Spring Boot 和 ShedLock 来演示如何解决定时任务的重复执行问题。希望能给大家一个参考!

❶ 添加依赖

首先确保www.chinasem.cn我们的的 pom.XML 中包含必要的依赖。需要添加 Spring Boot Starter、Spring Scheduling 和 ShedLock 相关的依赖。

其中博主使用的是mysql作为ShedLock初始化数据库,引入shedlock-provider-jdbc-template,大家可以根据自己的实际情况,根据作者的文档选择,如下图:

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Spring Boot Scheduler -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-scheduled</artifactId>
    </dependency>
    <!-- ShedLock Core -->
    <dependency>
        <groupId>net.javacrumbs.shedlock</groupId>
        <artifactId>shedlock-spring</artifactId>
        <version>6.2.0</version>
    </dependency>
    <!-- ShedLock JDBC -->
    <dependency>
        <groupId>net.javacrumbs.shedlock</groupId>
        <artifactId>shedlock-provider-jdbc-template</artifactId>
        <version>6.2.0</version>
    </dependency>
    <!-- MySQL JDBC Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

对应版本兼容性依赖:

ShedLock版本最低JVM版本Tested with
6.x.x17Spring 6.2, 6.1
Spring Boot 3.4, 3.3
Micronaut 4
5.x.x17Spring 6.1, 6.0
Spring Boot 3.4, 3.3, 3.2
Micronaut 3, 4
4.x.x8Spring 6.0, 5.3
Spring Boot 3.0, 2.7, 2.6
3.x.x8Spring 5.2, 5.1
Spring Boot 2.2, 2.1
2.x.x8Spring 5.1, 5.0
Spring Boot 2.1
1.x.x8Spring 5.0
Spring Boot 2.0

❷ 配置php数据库

ShedLock 需要在数据库中存储锁的信息。这里博主使用 MySQL 来存储puhopzIPse锁。首先,创建一个名为 shedlock 的表来存储锁数据。

CREATE TABLE shedlock (
    name VARCHAR(64) PRIMARY KEY,
    lock_until TIMESTAMP(3) NOT NULL,
    locked_at TIMESTAMP(3) NOT NULL,
    locked_by VARCHAR(255) NOT NULL
);

该表的字段意义如下:

  • name: 锁的名称,用于区分不同的任务。
  • lock_until: 锁的过期时间,任务完成后应释放锁。
  • locked_at: 锁的创建时间。
  • locked_by: 锁被哪个节点持有。

❸ 配置 ShedLock

接下来,我们在 Spring Boot 配置类中进行 ShedLock 的配置。以下是一个基本的配置类:

import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "30m") //默认锁最大过期时间为 30 秒
public class ShedLockConfig {
}

注解说明:
@EnableSchedulerLock: 启用 ShedLock 功能,defaultLockAtMostFor 参数指定锁的最大过期时间。js如果任务执行超过此时间,锁将会被释放。

@EnableScheduling: 启用 Spring 的调度功能。

❹ 创建定时任务

接下来我们创建一个定时任务,并为其添加 ShedLock 锁,确保在分布式环境中只有一个实例会执行该任务。

package com.example;
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class DataSyncService {
    /**
     * 使用 @SchedulerLock 注解来确保该任务只会在一个节点上执行
     */
    @Scheduled(fixedRate = 5000)  // 每 5 秒执行一次
    @SchedulerLock(name = "syncInventoryTask", lockAtMostFor = "5m", lockAtLeastFor = "5m")
    public void syncInventory() {
        System.out.println("同步库存数据...");
        // 模拟库存同步操作
        try {
            Thread.sleep(3000);  // 模拟执行耗时 3 秒
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("库存同步完成!");
    }
}

上述代码中,我们在在 syncInventory 方法上,我们使用了 @SchedulerLock 注解,指定锁的名称 syncInventoryTask,并设置锁的最大持续时间为 5 秒。

  • name: 锁的名称,确保每个定时任务有唯一的名称。
  • lockAtMostFor: 锁的最大过期时间,防止任务因为异常而无法释放锁。
  • lockAtLeastFor: 锁的最小持续时间,确保锁至少保持一定时间。

❺ 配置数据库连接

最后 application.properties 或 application.yml 配置我们的数据库连接信息

spring.datasource.url=jdbc:mysql://localhost:3306/your_database
spring.datasource.username=root
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

❻ 启动应用测试

最后我们启动 Spring Boot 应用,查看控制台输出。你将会看到 syncInventory 任务每 5 秒钟执行一次,但只有一个节点能够在任何时刻成功执行该任务,避免了多节点并发执行造成的问题。

总结

相信小伙伴们通过本文的示例,我们演示了如何使用 ShedLock 解决分布式系统中定时任务重复执行的问题。ShedLock 提供了一种简单有效的方式来确保在多实例部署的环境中,定时任务不会被重复执行,避免了数据不一致等问题。

  • 应用场景: 分布式定时任务、任务调度、数据同步等场景。
  • 优势: 简单易用、无需复杂配置、适配多种存储方式(如 JDBC、MongoDBRedis等)

到此这篇关于Spring Boot 整合 ShedLock 处理定时任务重复执行的问题的文章就介绍到这了,更多相关Spring Boot ShedLock 定时任务重复执行内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153322

相关文章

使用Java发送邮件到QQ邮箱的完整指南

《使用Java发送邮件到QQ邮箱的完整指南》在现代软件开发中,邮件发送功能是一个常见的需求,无论是用户注册验证、密码重置,还是系统通知,邮件都是一种重要的通信方式,本文将详细介绍如何使用Java编写程... 目录引言1. 准备工作1.1 获取QQ邮箱的SMTP授权码1.2 添加JavaMail依赖2. 实现

Java嵌套for循环优化方案分享

《Java嵌套for循环优化方案分享》介绍了Java中嵌套for循环的优化方法,包括减少循环次数、合并循环、使用更高效的数据结构、并行处理、预处理和缓存、算法优化、尽量减少对象创建以及本地变量优化,通... 目录Java 嵌套 for 循环优化方案1. 减少循环次数2. 合并循环3. 使用更高效的数据结构4

java两个List的交集,并集方式

《java两个List的交集,并集方式》文章主要介绍了Java中两个List的交集和并集的处理方法,推荐使用Apache的CollectionUtils工具类,因为它简单且不会改变原有集合,同时,文章... 目录Java两个List的交集,并集方法一方法二方法三总结java两个List的交集,并集方法一

Spring AI集成DeepSeek三步搞定Java智能应用的详细过程

《SpringAI集成DeepSeek三步搞定Java智能应用的详细过程》本文介绍了如何使用SpringAI集成DeepSeek,一个国内顶尖的多模态大模型,SpringAI提供了一套统一的接口,简... 目录DeepSeek 介绍Spring AI 是什么?Spring AI 的主要功能包括1、环境准备2

Spring AI集成DeepSeek实现流式输出的操作方法

《SpringAI集成DeepSeek实现流式输出的操作方法》本文介绍了如何在SpringBoot中使用Sse(Server-SentEvents)技术实现流式输出,后端使用SpringMVC中的S... 目录一、后端代码二、前端代码三、运行项目小天有话说题外话参考资料前面一篇文章我们实现了《Spring

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav

Springboot的自动配置是什么及注意事项

《Springboot的自动配置是什么及注意事项》SpringBoot的自动配置(Auto-configuration)是指框架根据项目的依赖和应用程序的环境自动配置Spring应用上下文中的Bean... 目录核心概念:自动配置的关键特点:自动配置工作原理:示例:需要注意的点1.默认配置可能不适合所有场景

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

Java8需要知道的4个函数式接口简单教程

《Java8需要知道的4个函数式接口简单教程》:本文主要介绍Java8中引入的函数式接口,包括Consumer、Supplier、Predicate和Function,以及它们的用法和特点,文中... 目录什么是函数是接口?Consumer接口定义核心特点注意事项常见用法1.基本用法2.结合andThen链

spring @EventListener 事件与监听的示例详解

《spring@EventListener事件与监听的示例详解》本文介绍了自定义Spring事件和监听器的方法,包括如何发布事件、监听事件以及如何处理异步事件,通过示例代码和日志,展示了事件的顺序... 目录1、自定义Application Event2、自定义监听3、测试4、源代码5、其他5.1 顺序执行