SpringBoot整合ShedLock解決定時(shí)任務(wù)防止重復(fù)執(zhí)行的問(wèn)題
在分布式系統(tǒng)中,尤其是涉及到定時(shí)任務(wù)的場(chǎng)景下,任務(wù)的重復(fù)執(zhí)行是一個(gè)常見(jiàn)問(wèn)題。例如,多個(gè)服務(wù)節(jié)點(diǎn)同時(shí)執(zhí)行同一個(gè)定時(shí)任務(wù),可能會(huì)導(dǎo)致數(shù)據(jù)重復(fù)處理或者資源爭(zhēng)用。ShedLock 是一個(gè)解決分布式環(huán)境中定時(shí)任務(wù)重復(fù)執(zhí)行問(wèn)題的庫(kù),它通過(guò)使用數(shù)據(jù)庫(kù)鎖機(jī)制確保只有一個(gè)節(jié)點(diǎn)執(zhí)行特定的定時(shí)任務(wù)。
ShedLock 的工作原理
ShedLock 通過(guò)對(duì)任務(wù)加鎖來(lái)避免多個(gè)實(shí)例(多個(gè)節(jié)點(diǎn))執(zhí)行同一個(gè)定時(shí)任務(wù)。它依賴于數(shù)據(jù)庫(kù)表來(lái)存儲(chǔ)任務(wù)的鎖信息。每次執(zhí)行任務(wù)之前,ShedLock 會(huì)檢查數(shù)據(jù)庫(kù)中是否有其他節(jié)點(diǎn)已經(jīng)獲得鎖。如果沒(méi)有,它會(huì)設(shè)置鎖并執(zhí)行任務(wù);如果有,任務(wù)會(huì)被跳過(guò)。
添加依賴
在 Spring Boot 項(xiàng)目中集成 ShedLock,需要在 pom.xml 中添加相關(guān)依賴。
<dependencies> <!-- ShedLock核心庫(kù) --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>6.2.0</version> <!-- 最新版本 --> </dependency> <!-- ShedLock數(shù)據(jù)庫(kù)存儲(chǔ)實(shí)現(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ù)庫(kù),例如 H2 或 MySQL --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies>
創(chuàng)建數(shù)據(jù)庫(kù)表
在使用 ShedLock 時(shí),需要?jiǎng)?chuàng)建一個(gè)數(shù)據(jù)庫(kù)表來(lái)存儲(chǔ)鎖的狀態(tài)。以下是示例的 SQL 腳本,適用于 MySQL 或其他關(guān)系型數(shù)據(jù)庫(kù)。
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ù)庫(kù)存儲(chǔ)和鎖提供者。
配置類 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") // 默認(rèn)任務(wù)最長(zhǎng)執(zhí)行時(shí)間 30 分鐘 @EnableJpaRepositories("net.javacrumbs.shedlock.provider.jparepository") // 啟用 JPA 存儲(chǔ)庫(kù) public class ShedLockConfig { @Bean public LockProvider lockProvider(EntityManager entityManager) { return new JpaLockProvider(entityManager); // 使用 JPA 實(shí)現(xiàn)的鎖提供者 } }
創(chuàng)建定時(shí)任務(wù)
接下來(lái),你可以通過(guò) @Scheduled 注解定義定時(shí)任務(wù),并使用 @SchedulerLock 注解來(lái)確保任務(wù)不會(huì)在多個(gè)節(jié)點(diǎn)上同時(shí)執(zhí)行。
示例:定時(shí)任務(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ù)不會(huì)被重復(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 注解通過(guò) name 參數(shù)來(lái)標(biāo)識(shí)任務(wù)名稱,確保相同名稱的任務(wù)只會(huì)由一個(gè)節(jié)點(diǎn)執(zhí)行。lockAtMostFor 和 lockAtLeastFor 分別表示任務(wù)最多和最少保持鎖定的時(shí)間,防止任務(wù)執(zhí)行時(shí)間過(guò)短或過(guò)長(zhǎng)。
- lockAtMostFor:設(shè)置任務(wù)執(zhí)行時(shí),最多持有鎖的時(shí)間。如果任務(wù)執(zhí)行時(shí)間超過(guò)該時(shí)間,鎖將被釋放。
- lockAtLeastFor:設(shè)置任務(wù)至少持有鎖的時(shí)間,防止任務(wù)執(zhí)行過(guò)快而過(guò)早釋放鎖。
啟用 Spring Boot 定時(shí)任務(wù)功能
確保啟用了 Spring Boot 的定時(shí)任務(wù)功能。你可以在 application.properties 或 application.yml 中配置相關(guān)屬性,或者在啟動(dòng)類中啟用 @EnableScheduling。
application.properties 配置:
spring.scheduling.enabled=true
或者在主啟動(dòng)類上使用 @EnableScheduling 注解啟用定時(shí)任務(wù):
主啟動(dòng)類 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)定時(shí)任務(wù)被觸發(fā)時(shí),ShedLock 會(huì)嘗試獲取鎖。如果任務(wù)已經(jīng)有鎖,其他節(jié)點(diǎn)會(huì)跳過(guò)該任務(wù)的執(zhí)行。
分布式鎖:通過(guò)數(shù)據(jù)庫(kù)表,ShedLock 確保分布式環(huán)境中多個(gè)服務(wù)實(shí)例不會(huì)同時(shí)執(zhí)行相同的任務(wù),避免了重復(fù)執(zhí)行的問(wèn)題。
防止任務(wù)阻塞:如果任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),ShedLock 會(huì)根據(jù)配置自動(dòng)釋放鎖,防止任務(wù)被阻塞。
其他配置
你可以通過(guò)配置 defaultLockAtMostFor 和 defaultLockAtLeastFor 來(lái)全局設(shè)置鎖的過(guò)期時(shí)間。defaultLockAtMostFor 表示全局配置的任務(wù)最長(zhǎng)執(zhí)行時(shí)間,defaultLockAtLeastFor 則表示全局配置的任務(wù)最短執(zhí)行時(shí)間。
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M", defaultLockAtLeastFor = "PT30S")
這樣,所有使用 @SchedulerLock 注解的任務(wù)都將遵循這些全局設(shè)置,除非你在注解中顯式地覆蓋它們。
在 ShedLock 6.2.0 中,集成方式?jīng)]有太大變化,但提供了更強(qiáng)的配置靈活性和優(yōu)化。在分布式系統(tǒng)中,ShedLock 可以確保定時(shí)任務(wù)只會(huì)被一個(gè)實(shí)例執(zhí)行,有效避免了重復(fù)執(zhí)行的問(wèn)題。通過(guò)數(shù)據(jù)庫(kù)存儲(chǔ)鎖,ShedLock 使得定時(shí)任務(wù)管理更加可靠,適用于高并發(fā)和分布式的應(yīng)用場(chǎng)景。
通過(guò)上述步驟,你可以輕松地在 Spring Boot 項(xiàng)目中使用 ShedLock 來(lái)管理定時(shí)任務(wù),確保任務(wù)不會(huì)被重復(fù)執(zhí)行,提升系統(tǒng)的穩(wěn)定性和性能。
到此這篇關(guān)于SpringBoot整合ShedLock解決定時(shí)任務(wù)防止重復(fù)執(zhí)行的問(wèn)題的文章就介紹到這了,更多相關(guān)SpringBoot ShedLock防止重復(fù)執(zhí)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
設(shè)計(jì)模式之構(gòu)建(Builder)模式 建造房子實(shí)例分析
構(gòu)建模式主要用來(lái)針對(duì)復(fù)雜產(chǎn)品生產(chǎn),分離部件構(gòu)建細(xì)節(jié),以達(dá)到良好的伸縮性,考慮到設(shè)計(jì)模式來(lái)源于建筑學(xué),因此舉一個(gè)建造房子的例子,需要的朋友可以參考下2012-12-12Java四種訪問(wèn)控制修飾符知識(shí)點(diǎn)總結(jié)
本篇文章給大家詳細(xì)分析了Java四種訪問(wèn)控制修飾符的相關(guān)知識(shí)點(diǎn),有興趣的朋友可以參考學(xué)習(xí)下。2018-03-03SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解
這篇文章主要介紹了SpringBoot在RequestBody中使用枚舉參數(shù)案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09Spring中byName和byType的區(qū)別及說(shuō)明
這篇文章主要介紹了Spring中byName和byType的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12JSONArray在Java中的應(yīng)用操作實(shí)例
JSONArray是org.json庫(kù)用于處理JSON數(shù)組的類,可將Java對(duì)象(Map/List)轉(zhuǎn)換為JSON格式,提供增刪改查等操作,適用于前后端數(shù)據(jù)交互,并涵蓋安全、性能優(yōu)化及最佳實(shí)踐,本文給大家介紹JSONArray在Java中的應(yīng)用,感興趣的朋友一起看看吧2025-07-07SpringBoot使用RestTemplate實(shí)現(xiàn)HTTP請(qǐng)求詳解
這篇文章主要為大家詳細(xì)介紹了SpringBoot如何使用RestTemplate實(shí)現(xiàn)進(jìn)行HTTP請(qǐng)求,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03