SpringBoot整合ShedLock解決定時任務(wù)防止重復(fù)執(zhí)行的問題
在分布式系統(tǒng)中,尤其是涉及到定時任務(wù)的場景下,任務(wù)的重復(fù)執(zhí)行是一個常見問題。例如,多個服務(wù)節(jié)點同時執(zhí)行同一個定時任務(wù),可能會導(dǎo)致數(shù)據(jù)重復(fù)處理或者資源爭用。ShedLock 是一個解決分布式環(huán)境中定時任務(wù)重復(fù)執(zhí)行問題的庫,它通過使用數(shù)據(jù)庫鎖機制確保只有一個節(jié)點執(zhí)行特定的定時任務(wù)。
ShedLock 的工作原理
ShedLock 通過對任務(wù)加鎖來避免多個實例(多個節(jié)點)執(zhí)行同一個定時任務(wù)。它依賴于數(shù)據(jù)庫表來存儲任務(wù)的鎖信息。每次執(zhí)行任務(wù)之前,ShedLock 會檢查數(shù)據(jù)庫中是否有其他節(jié)點已經(jīng)獲得鎖。如果沒有,它會設(shè)置鎖并執(zhí)行任務(wù);如果有,任務(wù)會被跳過。
添加依賴
在 Spring Boot 項目中集成 ShedLock,需要在 pom.xml 中添加相關(guān)依賴。
<dependencies> <!-- ShedLock核心庫 --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>6.2.0</version> <!-- 最新版本 --> </dependency> <!-- ShedLock數(shù)據(jù)庫存儲實現(xiàn)(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> <!-- 選擇合適的數(shù)據(jù)庫,例如 H2 或 MySQL --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies>
創(chuàng)建數(shù)據(jù)庫表
在使用 ShedLock 時,需要創(chuàng)建一個數(shù)據(jù)庫表來存儲鎖的狀態(tài)。以下是示例的 SQL 腳本,適用于 MySQL 或其他關(guān)系型數(shù)據(jù)庫。
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 數(shù)據(jù)源
然后,在 Spring Boot 配置類中啟用 ShedLock,配置數(shù)據(jù)庫存儲和鎖提供者。
配置類 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") // 默認任務(wù)最長執(zhí)行時間 30 分鐘 @EnableJpaRepositories("net.javacrumbs.shedlock.provider.jparepository") // 啟用 JPA 存儲庫 public class ShedLockConfig { @Bean public LockProvider lockProvider(EntityManager entityManager) { return new JpaLockProvider(entityManager); // 使用 JPA 實現(xiàn)的鎖提供者 } }
創(chuàng)建定時任務(wù)
接下來,你可以通過 @Scheduled 注解定義定時任務(wù),并使用 @SchedulerLock 注解來確保任務(wù)不會在多個節(jié)點上同時執(zhí)行。
示例:定時任務(wù) ScheduledTasks.java:
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class ScheduledTasks { // 每分鐘執(zhí)行一次任務(wù),使用 ShedLock 確保任務(wù)不會被重復(fù)執(zhí)行 @Scheduled(cron = "0 * * * * ?") @SchedulerLock(name = "exampleTask", lockAtMostFor = "PT30S", lockAtLeastFor = "PT30S") public void exampleTask() { System.out.println("Executing example task..."); // 任務(wù)邏輯,例如更新數(shù)據(jù)、發(fā)送通知等 } }
在上述代碼中,@SchedulerLock 注解通過 name 參數(shù)來標識任務(wù)名稱,確保相同名稱的任務(wù)只會由一個節(jié)點執(zhí)行。lockAtMostFor 和 lockAtLeastFor 分別表示任務(wù)最多和最少保持鎖定的時間,防止任務(wù)執(zhí)行時間過短或過長。
- lockAtMostFor:設(shè)置任務(wù)執(zhí)行時,最多持有鎖的時間。如果任務(wù)執(zhí)行時間超過該時間,鎖將被釋放。
- lockAtLeastFor:設(shè)置任務(wù)至少持有鎖的時間,防止任務(wù)執(zhí)行過快而過早釋放鎖。
啟用 Spring Boot 定時任務(wù)功能
確保啟用了 Spring Boot 的定時任務(wù)功能。你可以在 application.properties 或 application.yml 中配置相關(guān)屬性,或者在啟動類中啟用 @EnableScheduling。
application.properties 配置:
spring.scheduling.enabled=true
或者在主啟動類上使用 @EnableScheduling 注解啟用定時任務(wù):
主啟動類 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); } }
工作原理
鎖定任務(wù):當(dāng)定時任務(wù)被觸發(fā)時,ShedLock 會嘗試獲取鎖。如果任務(wù)已經(jīng)有鎖,其他節(jié)點會跳過該任務(wù)的執(zhí)行。
分布式鎖:通過數(shù)據(jù)庫表,ShedLock 確保分布式環(huán)境中多個服務(wù)實例不會同時執(zhí)行相同的任務(wù),避免了重復(fù)執(zhí)行的問題。
防止任務(wù)阻塞:如果任務(wù)執(zhí)行時間過長,ShedLock 會根據(jù)配置自動釋放鎖,防止任務(wù)被阻塞。
其他配置
你可以通過配置 defaultLockAtMostFor 和 defaultLockAtLeastFor 來全局設(shè)置鎖的過期時間。defaultLockAtMostFor 表示全局配置的任務(wù)最長執(zhí)行時間,defaultLockAtLeastFor 則表示全局配置的任務(wù)最短執(zhí)行時間。
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M", defaultLockAtLeastFor = "PT30S")
這樣,所有使用 @SchedulerLock 注解的任務(wù)都將遵循這些全局設(shè)置,除非你在注解中顯式地覆蓋它們。
在 ShedLock 6.2.0 中,集成方式?jīng)]有太大變化,但提供了更強的配置靈活性和優(yōu)化。在分布式系統(tǒng)中,ShedLock 可以確保定時任務(wù)只會被一個實例執(zhí)行,有效避免了重復(fù)執(zhí)行的問題。通過數(shù)據(jù)庫存儲鎖,ShedLock 使得定時任務(wù)管理更加可靠,適用于高并發(fā)和分布式的應(yīng)用場景。
通過上述步驟,你可以輕松地在 Spring Boot 項目中使用 ShedLock 來管理定時任務(wù),確保任務(wù)不會被重復(fù)執(zhí)行,提升系統(tǒng)的穩(wěn)定性和性能。
到此這篇關(guān)于SpringBoot整合ShedLock解決定時任務(wù)防止重復(fù)執(zhí)行的問題的文章就介紹到這了,更多相關(guān)SpringBoot ShedLock防止重復(fù)執(zhí)行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Java操作MySQL實現(xiàn)數(shù)據(jù)交互的方法
JDBC是Java中用于操作數(shù)據(jù)庫的API,可以為多種關(guān)系數(shù)據(jù)庫提供統(tǒng)一訪問,它通過JDK自帶的JDBC API和數(shù)據(jù)庫驅(qū)動包進行操作,實現(xiàn)數(shù)據(jù)庫的增刪改查,本文給大家介紹使用Java操作MySQL實現(xiàn)數(shù)據(jù)交互的方法,感興趣的朋友跟隨小編一起看看吧2025-01-01淺析對Java關(guān)鍵字final和static的理解
本文主要給大家談?wù)勑【帉ava關(guān)鍵字final和static的理解,本文給大家介紹的較詳細,需要的朋友參考參考下2017-04-04java 中序列化與readResolve()方法的實例詳解
這篇文章主要介紹了java 中序列化與readResolve()方法的實例詳解的相關(guān)資料,這里提供實例幫助大家理解這部分知識,需要的朋友可以參考下2017-08-08Java存儲過程調(diào)用CallableStatement的方法
這篇文章主要介紹了Java存儲過程調(diào)用CallableStatement的方法,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下2020-11-11spring mvc中直接注入的HttpServletRequst安全嗎
這篇文章主要給大家介紹了關(guān)于spring mvc中直接注入的HttpServletRequst是不是安全的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2018-04-04Spring Cloud Alibaba Nacos 入門詳解
這篇文章主要介紹了Spring Cloud Alibaba Nacos入門詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03