转笔教学网站,下载的asp网站怎么打开,山西省建设资格注册中心网站,河北港网站建设在Spring Boot 3中实现分布式定时任务#xff0c;确保多实例环境下任务仅执行一次#xff0c;可以采用以下方案#xff1a; 方案一#xff1a;Redis分布式锁#xff08;推荐#xff09;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.sp…在Spring Boot 3中实现分布式定时任务确保多实例环境下任务仅执行一次可以采用以下方案 方案一Redis分布式锁推荐
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.concurrent.TimeUnit;Component
public class DistributedScheduler {private final StringRedisTemplate redisTemplate;private static final String LOCK_KEY TASK_LOCK:MY_TASK;private static final int LOCK_TIMEOUT 9; // 锁超时时间分钟public DistributedScheduler(StringRedisTemplate redisTemplate) {this.redisTemplate redisTemplate;}Scheduled(cron 0 */10 * * * *)public void scheduledTask() {Boolean lockAcquired redisTemplate.opsForValue().setIfAbsent(LOCK_KEY, locked, Duration.ofMinutes(LOCK_TIMEOUT));if (lockAcquired ! null lockAcquired) {try {// 执行任务逻辑performTask();} finally {// 任务完成后手动释放锁可选// redisTemplate.delete(LOCK_KEY);}}}private void performTask() {// 具体任务代码System.out.println(Task executed at: new Date());}
}依赖配置
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency关键点
使用 setIfAbsent 原子性操作获取锁避免并发问题。设置锁的自动过期时间略小于任务间隔防止死锁。根据业务需求选择是否手动释放锁如任务执行时间可能超过锁超时时间。 方案二数据库乐观锁
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;Component
public class DatabaseLockScheduler {Scheduled(cron 0 */10 * * * *)Transactionalpublic void scheduledTask() {// 1. 查询最近一次任务记录TaskLock lastLock taskLockRepository.findTopByTaskNameOrderByExecuteTimeDesc(MY_TASK);// 2. 检查是否已执行过if (lastLock ! null lastLock.getExecuteTime().isAfter(LocalDateTime.now().minusMinutes(10))) {return;}// 3. 插入新记录利用唯一约束或版本号控制并发TaskLock newLock new TaskLock(MY_TASK, LocalDateTime.now());taskLockRepository.save(newLock);// 执行任务逻辑performTask();}
}实体类示例
Entity
public class TaskLock {Idprivate String taskName;private LocalDateTime executeTime;Versionprivate Integer version;// 省略构造方法/getter/setter
}关键点
使用数据库唯一约束复合唯一索引或版本号控制并发。需要处理可能的异常如唯一约束冲突。 方案三Quartz集群模式
配置步骤
添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-quartz/artifactId
/dependency配置数据库存储application.properties
spring.quartz.job-store-typejdbc
spring.quartz.properties.org.quartz.jobStore.isClusteredtrue
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval20000定义任务
public class MyJob implements Job {Overridepublic void execute(JobExecutionContext context) {// 任务逻辑}
}配置调度器
Configuration
public class QuartzConfig {Beanpublic JobDetail jobDetail() {return JobBuilder.newJob(MyJob.class).withIdentity(myTask).storeDurably().build();}Beanpublic Trigger trigger() {return TriggerBuilder.newTrigger().forJob(jobDetail()).withSchedule(CronScheduleBuilder.cronSchedule(0 */10 * * * ?)).build();}
}方案对比
方案优点缺点Redis锁实现简单性能高依赖Redis需处理锁续期问题数据库锁无需额外中间件数据库压力大需处理并发冲突Quartz集群官方集群支持功能强大配置复杂依赖数据库表结构
选择建议
轻量级场景优先使用Redis锁已有数据库基础设施可考虑数据库锁复杂调度需求选择Quartz集群