定时任务 Spring Task 实现

3 阅读2分钟

1、Spring 定时任务

定时任务Scheduled Task)指的是按照指定的时间或时间间隔,自动执行的任务。

在应用程序中通常用于自动化处理一些定期或周期性的操作,特别是与时间相关的任务。

应用场景

  • 数据统计与报表生成
  • 缓存清理与刷新:自动清理过期数据
  • 数据同步与备份
  • 系统监控与告警
  • 消息发送与通知:自动发送邮件

1.1 执行方式

  1. 固定间隔执行

    • 使用 fixedRate 或 fixedDelay
    • fixedRate: 每隔固定时间执行一次(开始时间到开始时间)
    • fixedDelay: 上一次任务完成后延迟固定时间再执行
  2. Cron 表达式执行

    • 使用 cron 表达式,可以精确控制执行时间(每天、每周、每月等)
    • 表达式格式:秒 分 时 日 月 星期
  3. 触发器任务

    • Spring 还支持基于触发器(Trigger)的复杂任务调度,可以动态控制下次执行时间

2、定时任务 Spring Task 实现

2.1 开启定时任务

引入 Spring 的定时任务依赖:Spring Boot 中启用定时任务添加 @EnableScheduling 注解

@SpringBootApplication
@MapperScan("com.hospital.mapper")
@EnableCaching
@EnableScheduling  // 开启定时任务
public class SpringBootSystemApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootSystemApplication.class, args);
    }
}

2.2 创建定时任务类

使用 @Scheduled 注解来定义执行周期和任务,创建AppointmentTask,实现自动取消过期预约

package com.example.task;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.example.entity.Appointment;
import com.example.mapper.AppointmentMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;

@Slf4j
@Component
public class AppointmentTask {

    @Autowired
    private AppointmentMapper appointmentMapper;

    /**
     * 每天凌晨1点执行,将已过期未就诊的预约状态改为"已过期"
     * cron表达式:秒 分 时 日 月 星期
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void cancelExpiredAppointments() {
        log.info("开始执行过期预约取消任务");
        // 获取当前日期之前的所有预约(预约日期小于今天)
        Date today = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
        LambdaUpdateWrapper<Appointment> wrapper = new LambdaUpdateWrapper<>();
        wrapper.lt(Appointment::getAppointmentDate, today)
               .eq(Appointment::getStatus, "已预约")
               .set(Appointment::getStatus, "已过期");
        int rows = appointmentMapper.update(null, wrapper);
        log.info("过期预约取消任务完成,共更新{}条记录", rows);
    }

    /**
     * 测试用:每30秒执行一次(取消后注释)
     */
    // @Scheduled(fixedDelay = 30000)
    // public void testTask() {
    //     log.info("定时任务测试");
    // }
}