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

如何用 ShedLock 让 Spring Boot 的定时任务在多实例环境下只执行一次

之前在Spring Boot教程中我们介绍了如何用 @Scheduled 注解来创建定时任务,Spring 的任务调度用起来确实顺手。可这种实现方式一上多实例(比如多副本部署),同一个定时任务会在每个节点都跑一遍,等于任务会重复执行。

原因很简单:默认情况下,Spring 不会在多个实例之间做调度同步。

这篇文章就聊聊怎么用 ShedLock,让定时任务在多实例环境下“同一时刻只跑一次”。顺便一提,它也能作为 Quartz 的替代。

Maven 依赖

先引入 shedlock-spring 这个依赖:

<dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-spring</artifactId><version>6.3.1</version>
</dependency>

最新版本可以去 Maven Central 看。

配置

ShedLock 依赖“共享数据库”,并且要声明一个合适的 LockProvider。它会在库里新建一张表/文档,记录当前的锁。

目前它支持 Mongo、Couchbase、Elasticsearch、Redis、Hazelcast、ZooKeeper、Cassandra,以及任何带 JDBC 驱动的数据库。

示例我们用内存型 H2 数据库,方便演示。

要跑起来,先把 H2 和 JDBC 版的 ShedLock 依赖加上:

<dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-provider-jdbc-template</artifactId><version>6.3.1</version>
</dependency>
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>2.1.214</version>
</dependency>

然后建一张表,专门存锁:

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

在 Spring Boot 里把数据源写到配置里,这样 DataSource 才能被注入。这里用 application.yml:

spring:datasource:driverClassName: org.h2.Driverurl: jdbc:h2:mem:shedlock_DB;INIT=CREATE SCHEMA IF NOT EXISTS shedlock;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSEusername: sapassword:

接着用这个数据源配置下 LockProvider,写法很直观:

@Configuration
public class SchedulerConfiguration {@Beanpublic LockProvider lockProvider(DataSource dataSource) {return new JdbcTemplateLockProvider(dataSource);}
}

别忘了再加上两个注解:@EnableScheduling 和 @EnableSchedulerLock:

@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SpringBootShedlockApplication {public static void main(String[] args) {SpringApplication.run(SpringBootShedlockApplication.class, args);}
}

defaultLockAtMostFor 表示执行节点挂了时,锁最多保留多久。格式用的是 ISO8601 持续时间。

下面的示例会演示怎么在方法上覆盖它。

创建任务

让 ShedLock 接管一个定时任务很简单:方法上同时加 @Scheduled 和 @SchedulerLock:

@Component
class BaeldungTaskScheduler {@Scheduled(cron = "0 0/15 * * * ?")@SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtLeastFor = "PT5M", lockAtMostFor = "PT14M")public void scheduledTask() {// ...}
}

先说 @Scheduled:它支持 cron 表达式,上面的表达式表示“每 15 分钟执行一次”。

再说 @SchedulerLock:name 要唯一,一般用 类名_方法名 就够了。我们不希望同一个方法被同时运行,ShedLock 就是靠这个唯一名称来实现的。

我们还加了两个可选参数:

  • lockAtLeastFor 用来保证最少持锁时间,让两次执行之间留出一定间隔。使用 “PT5M” 表示至少 5 分钟。换句话说,这个方法被 ShedLock 控制后,运行频率不会高于每 5 分钟一次。
  • lockAtMostFor 用来指定在执行节点异常(比如宕机)时,锁最多会被保留多久。使用 “PT14M” 表示最多 14 分钟。

正常情况下任务结束会立即释放锁。其实在 @EnableSchedulerLock 里已经有默认值,这里只是展示如何在方法级别做覆盖。

总结

一句话总结:用 ShedLock,可以让 Spring 在多实例部署下也能把定时任务“稳稳只跑一次”。

http://www.zskr.cn/news/13461.html

相关文章:

  • 故障处理:Oracle表空间异常增长后又恢复正常的故障模拟与分析
  • ​​万用表与电流探头测量电流信号的技术对比分析​​
  • flink运行时架构 - --
  • WPF Canvas mark triangle, circle, and retangle, then save the whole canvas as jpg file
  • wifi亮灭屏机制--系统修改
  • 得帆云ETL全新版本升级驱动数据高效流转
  • 地图商业授权共享 - no
  • 【Array】数组:多个值的集合
  • 第一次算法分析作业
  • 2025 年过滤器品牌权威推荐排行榜:TOP5 企业技术实力测评,覆盖化工 / 环保 / 空气净化等多场景最新选型指南
  • [Golang] golang安装
  • web3实战工程 - hardhat框架
  • 重组蛋白表达中包涵体的形成与优化策略
  • 【MySQL】性能优化与核心机制深度解析 - 详解
  • B4375 [蓝桥杯青少年组省赛 2025] 庆典队列B4376 [蓝桥杯青少年组省赛 2025] 茶具套装B4377 [蓝桥杯青少年组省赛 2025] 平衡奇偶位置的字符交换
  • 神经网络常见的40多种激活函数(应用场景+数学公式+代码实现+函数图象)
  • 详细介绍:C++基础(22)——模板的进阶
  • 题解:[GESP202509 五级] T1
  • US$39.9 Scorpio-LK Emulators SLK-06 for Tango Key Programmer
  • 2025无人机在低空应急救援中的应用实践
  • 记录,结构,枚举,ref,in和out 元组
  • Flutter - dart 语言从入门到精通 - 教程
  • 哈夫曼编码例题
  • Win11共享打印0x0000bc4,三步解决共享难题
  • Atlas Mapper 教程系列 (7/10):单元测试与集成测试 - 教程
  • 【WCH蓝牙系列芯片】-基于CH585开发板—IO口(GPIO)外部中断唤醒蓝牙睡眠模式
  • DevExpress WinForms v25.2新功能预览 - 即将升级富文本编辑器控件功能
  • redis-事务操作
  • 【Linux基础知识系列:第一百四十篇】理解SELinux与系统安全 - 教程
  • 关于修改 linux 系统中优先使用中文结构