网站开发 居易国际订单拆单在电商网站建设
2026/3/27 10:15:15 网站建设 项目流程
网站开发 居易国际,订单拆单在电商网站建设,百度资源分享网页,2007年怎么做网站Spring Boot 的 Scheduled 写定时任务很方便#xff0c;但多实例部署时有个问题#xff1a;同一个定时任务会在每台机器上都触发执行。比如部署了两台应用服务器#xff0c;凌晨 2 点的数据统计任务会同时跑两遍#xff0c;数据重复、文件重复生成。解决这个问题通常有几种…Spring Boot 的Scheduled写定时任务很方便但多实例部署时有个问题同一个定时任务会在每台机器上都触发执行。比如部署了两台应用服务器凌晨 2 点的数据统计任务会同时跑两遍数据重复、文件重复生成。解决这个问题通常有几种思路。常见方案方案一单机执行只在一台指定的机器上跑任务Scheduled(cron 0 0 2 * * ?) public void scheduledTask() { String hostname InetAddress.getLocalHost().getHostName(); if (!app-server-01.equals(hostname)) { return; } // do something }问题很明显那台机器挂了任务就不执行了。方案二Redis 分布式锁用 Redis 的 SETNX 实现互斥或者RedissionScheduled(cron 0 0 2 * * ?) public void scheduledTask() { Boolean locked stringRedisTemplate.opsForValue() .setIfAbsent(task:data-sync, 1, 10, TimeUnit.MINUTES); if (Boolean.FALSE.equals(locked)) { return; } try { // do something } finally { stringRedisTemplate.delete(task:data-sync); } }能用但每个任务都要写一遍加锁释放逻辑而且需要项目里有 Redis。ShedLock 方案ShedLock 是一个专门解决定时任务重复执行问题的框架支持多种存储后端数据库、Redis、MongoDB 等。核心思路在存储层记录每个任务的锁状态任务执行前先抢锁抢到了才执行。集成步骤1. 添加依赖dependency groupIdnet.javacrumbs.shedlock/groupId artifactIdshedlock-spring/artifactId version4.42.0/version /dependency dependency groupIdnet.javacrumbs.shedlock/groupId artifactIdshedlock-provider-jdbc-template/artifactId version4.42.0/version /dependency2. 创建锁表CREATE TABLE shedlock ( name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL, locked_at TIMESTAMP(3) NOT NULL, locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name) );3. 配置 LockProviderConfiguration EnableSchedulerLock(defaultLockAtMostFor 10m) public class ShedLockConfig { Bean public LockProvider lockProvider(DataSource dataSource) { return new JdbcTemplateLockProvider( JdbcTemplateLockProvider.Configuration.builder() .withDataSource(dataSource) .withTableName(shedlock) .build() ); } }4. 给定时任务加注解Scheduled(cron 0 0 2 * * ?) SchedulerLock(name dataSyncTask, lockAtMostFor 5m) public void syncData() { // do something }完成。多台服务器部署时只有抢到锁的那台会执行任务。注解参数说明SchedulerLock有几个关键参数name锁名称相同 name 的任务会互斥执行。建议用任务名来命名保持唯一。lockAtMostFor锁的最大持有时间。这是为了防止任务执行过程中机器宕机导致锁永远不释放。比如设置5m即使任务执行超时锁也会在 5 分钟后自动过期。一般按任务预期执行时间的 2 倍左右设置留些余量。lockAtLeastFor锁的最小持有时间。这是为了防止任务执行太快锁立即释放被其他机器抢到。比如定时任务每分钟执行一次任务 5 秒就跑完了。如果没有这个参数其他机器可能会在同一分钟内再次抢到锁执行。这种情况下可以设置lockAtLeastFor 1m确保锁保持到下一分钟。实现原理ShedLock 的实现逻辑不复杂。任务执行前会向数据库插入或更新锁记录INSERT INTO shedlock (name, lock_until, locked_at, locked_by) VALUES (dataSyncTask, 2025-01-25 02:05:00, NOW(), 192.168.1.10) ON DUPLICATE KEY UPDATE lock_until 2025-01-25 02:05:00, locked_at NOW(), locked_by 192.168.1.10 WHERE lock_until NOW();关键是最后的WHERE lock_until NOW()条件• 如果当前锁已过期UPDATE 成功抢到锁• 如果当前锁未过期UPDATE 影响行数为 0抢锁失败任务不执行任务执行完成后不需要主动释放锁等待lock_until时间到期即可。适用场景ShedLock 的定位很明确专门为定时任务设计的分布式锁框架。适合• 定时任务需要互斥执行避免重复• 希望用注解方式简化锁的代码逻辑• 需要自动锁过期机制防止死锁不适合• 高并发抢锁的业务场景比如秒杀、库存扣减ShedLock 不是为此设计• 需要可重入锁、读写锁等复杂特性• 需要精确控制锁获取和释放时机的业务逻辑ShedLock 和通用分布式锁是互补关系不是替代关系。如果你的业务代码里需要手动加锁解锁用 Redisson 或手动实现 Redis SETNX 更合适。但如果只是为了解决定时任务重复执行的问题ShedLock 是更简洁的方案。几个注意事项1. 存储后端选择本文演示用的是 JDBC 方式基于数据库表。ShedLock 还支持 Redis、MongoDB、ZooKeeper、Hazelcast 等多种存储后端根据项目现有技术栈选择即可。2. 表名自定义数据库存储时如果用 JDBC 作为存储后端默认表名是shedlock可以按需修改3. 机器标识locked_by字段记录是哪台机器拿到的锁默认是主机名。可以自定义成更有意义的标识.withLockedByValue(app- getServerIp())4. 主从/多数据源场景数据库存储时如果项目有多个数据源确保 ShedLock 用的是主库避免主从延迟导致的锁问题。总结ShedLock 是一个专门为定时任务设计的分布式锁框架• 优点注解式使用、集成简单、自动锁过期、支持多种存储后端• 局限性只适用于定时任务场景不适用于通用业务加锁和手动写 Redis 分布式锁相比ShedLock 把定时任务锁的逻辑抽象出来了代码更简洁。但如果你需要的是通用业务锁还是用 Redisson 或手写 SETNX 更合适。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询