Spring Boot 为什么要使用定时任务?什么时候用 @Scheduled?
在开发 Spring Boot 项目时,经常会遇到这样一种需求:
不是用户主动触发,而是希望程序自己在指定时间执行某项任务。
例如:
- 每天凌晨清理日志
- 每隔 5 分钟同步数据
- 每小时刷新缓存
- 每天统计文章阅读量
- 每月生成报表
这些需求都属于定时任务(Scheduled Task)。
Spring Boot 提供了 @Scheduled 注解,让我们几乎不用写额外代码,就能实现定时执行。
一、什么是定时任务?
定时任务,顾名思义,就是:
按照预先设定好的时间或周期,自动执行指定的任务。
例如:
每天凌晨 2 点
↓
自动备份数据库
或者:
每隔 10 分钟
↓
同步第三方数据
整个过程不需要用户点击按钮,也不需要人工操作。
只要应用程序一直运行,到达指定时间就会自动执行。
二、为什么要使用定时任务?
很多业务其实并不需要实时执行。
例如:
博客系统中,用户每阅读一次文章都会增加阅读量。
一种做法是:
用户阅读文章
↓
数据库 UPDATE
如果访问量很高,每一次阅读都更新数据库,压力会比较大。
另一种做法就是:
用户阅读文章
↓
Redis 统计阅读量
↓
每天凌晨同步数据库
这里每天凌晨同步数据库,就是一个典型的定时任务。
再比如缓存更新:
缓存
↓
30 分钟自动刷新一次
而不是等用户访问时才重新查询数据库。
这样可以提升接口响应速度。
三、Spring Boot 如何开启定时任务?
Spring Boot 提供了 @Scheduled 注解。
首先开启定时任务支持:
@SpringBootApplication
@EnableScheduling
public class BlogApplication {
public static void main(String[] args) {
SpringApplication.run(BlogApplication.class, args);
}
}
其中:
@EnableScheduling
表示开启 Spring Boot 的定时任务功能。
四、编写第一个定时任务
创建一个任务类:
@Component
public class ScheduleTask {
@Scheduled(fixedRate = 5000)
public void task(){
System.out.println("执行一次任务:" + LocalDateTime.now());
}
}
启动项目后,可以看到控制台每隔 5 秒输出一次日志。
这里:
fixedRate = 5000
表示:
以上一次任务开始执行时间为基准,每隔 5 秒执行一次。
五、常见的定时方式
Spring Boot 提供了几种常见的调度方式。
1、fixedRate
@Scheduled(fixedRate = 5000)
表示:
每隔 5 秒执行一次。
无论上一次任务是否执行结束,到达时间都会再次调度。
适用于:
- 数据采集
- 状态刷新
- 周期轮询
2、fixedDelay
@Scheduled(fixedDelay = 5000)
表示:
当前任务执行结束后,再等待 5 秒执行下一次。
例如:
任务执行 3 秒
↓
等待 5 秒
↓
再次执行
比较适合:
- 文件处理
- 数据同步
- 导出任务
保证同一个任务不会连续重叠执行。
3、cron
实际开发中使用最多的是:
@Scheduled(cron = "0 0 2 * * ?")
表示:
每天凌晨两点执行
例如:
@Scheduled(cron = "0 0 0 * * ?")
public void backup(){
}
每天零点自动备份数据库。
常见的 Cron 表达式:
| 表达式 | 含义 |
|---|---|
0 * * * * ? |
每分钟执行 |
0 */5 * * * ? |
每 5 分钟执行 |
0 0 * * * ? |
每小时执行 |
0 0 0 * * ? |
每天零点执行 |
0 0 2 * * ? |
每天凌晨两点执行 |
六、哪些场景适合使用定时任务?
Spring Boot 定时任务特别适合一些周期性执行的业务。
例如:
数据同步
ERP
↓
每隔 10 分钟同步
↓
本地数据库
缓存刷新
数据库
↓
每小时刷新 Redis
阅读量同步
Redis
↓
每天凌晨
↓
同步 MySQL
日志清理
每天凌晨
↓
删除 30 天以前日志
数据备份
每天凌晨 2 点
↓
自动备份数据库
报表生成
每月一号
↓
生成上个月统计报表
七、什么时候不建议使用定时任务?
如果业务需要立即执行,就不要使用定时任务。
例如:
用户下单:
创建订单
↓
扣减库存
↓
支付
↓
返回结果
库存不能等到半小时以后再扣。
支付也不能等到晚上再处理。
这类业务必须同步完成。
另外,如果任务依赖于外部事件,例如收到消息、文件上传完成等,也更适合采用消息队列或事件驱动,而不是固定时间轮询。
八、定时任务有哪些注意事项?
在实际开发中,需要注意以下几点:
- 定时任务不要执行耗时过长的操作,否则可能影响下一次调度。
- 如果任务比较耗时,可以结合线程池异步执行,提高执行效率。
- 多实例部署时,同一个定时任务可能会在每台服务器都执行一次,需要结合分布式锁或任务调度框架避免重复执行。
- 对于执行失败的任务,应做好日志记录和异常处理,方便排查问题。
九、总结
Spring Boot 提供的 @Scheduled 能够帮助我们快速实现定时任务,非常适合处理一些无需用户触发、需要周期执行的业务。
常见应用场景包括:
- 缓存刷新
- 数据同步
- 阅读量统计
- 日志清理
- 数据备份
- 报表生成
对于单体应用来说,@Scheduled 已经能够满足大部分需求。
如果后续项目演进为分布式架构,或者需要更复杂的任务调度能力,则可以进一步考虑使用 XXL-JOB、Quartz 等专业的调度框架。
掌握好 @Scheduled,不仅能够减少重复劳动,还能让许多后台任务实现自动化,提升系统的稳定性和运维效率。