Spring Boot集成Quartz触发器执行时间延迟8小时求助
问题:Spring Boot + Quartz 定时任务时区异常排查
环境与核心代码
1. 依赖引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
2. TimeJob 实体类
@Data @AllArgsConstructor @NoArgsConstructor @TableName("time_job") public class TimeJob { @Null(groups = {Add.class},message = "不允许指定id") @NotNull(groups = {Update.class},message = "不允许指定id") @TableId(type = IdType.AUTO) private Integer jobId; @NotBlank(groups = {Add.class,Update.class},message = "jobName不能为空") private String jobName; @Null(groups = {Add.class,Update.class},message = "不允许指定time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; @Null(groups = {Add.class,Update.class},message = "不允许指定time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; @NotBlank(groups = {Add.class,Update.class},message = "cron表达式不能为空") private String cronExpress; @Pattern(groups = {Add.class},regexp = "^\\[[1-9]+(,[1-9]+)*\\]$",message = "不符合数组规范") private String floorList; @NotNull(groups = {Add.class,Update.class},message = "startAt不能为空") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date startAt; @NotNull(groups = {Add.class,Update.class},message = "endAt不能为空") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date endAt; @NotNull(groups = {Add.class,Update.class},message = "enabled不能为空") private Boolean enabled; @NotNull(groups = {Add.class,Update.class},message = "UnitsId不能为空") private Integer unitsId; @Null(groups = {Add.class,Update.class},message = "不允许指定createBy") private Integer createBy; @Null(groups = {Add.class,Update.class},message = "不允许指定User name") @TableField(exist = false) private String createName; }
3. 新增任务接口
@PostMapping("/job") public CommonResult<String> addTimeJob(@RequestBody @Validated(Add.class) TimeJob timeJob) throws FloorFormatException, SchedulerException { int userId = StpUtil.getLoginIdAsInt(); timeJob.setCreateBy(userId); timeJob.setCreateTime(new Date()); timeJobService.saveJob(timeJob); return CommonResult.success("add success"); }
4. 保存任务核心逻辑
timeJobMapper.insert(timeJob); JobDetail jobDetail = JobBuilder.newJob(PubRedisByteJob.class) .usingJobData("data",ByteUtils.byteArrayTo0xStringArray(data)) .withIdentity(timeJob.getJobName()+":"+timeJob.getJobId().toString(),"PubRedisByteJob") .build(); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(timeJob.getJobName()+":"+timeJob.getJobId().toString(),"PubRedisByteTrigger") .startAt(timeJob.getStartAt()) .endAt(timeJob.getEndAt()) .withSchedule(CronScheduleBuilder.cronSchedule(timeJob.getCronExpress()) .inTimeZone(TimeZone.getTimeZone("Asia/Shanghai"))) .build(); scheduler.scheduleJob(jobDetail,trigger); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.info("next trigger time is {}",sdf.format(trigger.getNextFireTime()));
问题现象
传入参数:
{ "jobName": "test2", "cronExpress": "*/5 * * * * ?", "floorList": "[1]", "startAt": "2023-09-07 12:50:55", "endAt": "2023-09-08 12:50:55", "enabled": true, "remoteControlType": 1, "callUp": true, "unitsId": 26 }
控制台输出显示:
- 数据库插入的
startAt变为2023-09-07 20:50:55.0(比传入时间晚8小时) - 日志输出的下次触发时间为
2023-09-07 20:50:55
已尝试在application.yml和代码中指定Quartz时区为Asia/Shanghai,问题仍存在,求其他排查方案。
排查方案
- 修复JSON反序列化时区:给实体类的
@JsonFormat注解添加timezone = "Asia/Shanghai"参数,确保前端传入的本地时间字符串正确转换为上海时区的Date对象,避免默认UTC转换导致时间偏移。 - 修正数据库时区配置:检查数据库服务器时区,同时在JDBC连接URL中指定时区(如MySQL添加
&serverTimezone=Asia/Shanghai),保证存储和读取时间时的时区一致性。 - 全局配置Jackson时区:在
application.yml中配置Jackson默认使用上海时区:spring: jackson: time-zone: Asia/Shanghai - 强制JVM使用指定时区:启动应用时添加JVM参数
-Duser.timezone=Asia/Shanghai,覆盖系统默认时区,避免new Date()、日期格式化等操作出现时区偏差。 - 显式设置日志格式化时区:修改日志输出用的
SimpleDateFormat,指定上海时区,确保日志显示的时间与实际触发时间一致:SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); log.info("next trigger time is {}", sdf.format(trigger.getNextFireTime())); - 完善Quartz全局时区配置:在
application.yml中配置Quartz调度器的全局时区,确保所有Trigger默认使用该时区:spring: quartz: properties: org.quartz.scheduler.timezone: Asia/Shanghai - 验证Cron表达式逻辑:确认
*/5 * * * * ?在上海时区下的触发规则,可通过本地代码或离线工具验证表达式的执行周期是否符合预期。
内容的提问来源于stack exchange,提问作者liang li
相关产品推荐
相关产品推荐

