Quartz的使用(定时任务,包含SpringBoot的整合)

什么是Quartz

Quartz是一个由java编写的开源作业调度框架,简单来说,Quartz就是启动定时任务的框架,像linux系统中的corntab,可以定时启动任务.
Quartz的单独使用

Quartz的使用必须掌握下面三个对象

  • Scheduler 定时器对象

  • JobDetail 任务对象

  • Trigger 触发器对象

    SimpleTrigger 简单触发器
    CornTrigger任务调度触发器

使用案列

导入Maven依赖

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.2</version>
</dependency>

Job

/**
 * @author codekiller
 * @date 2020/6/4 23:31
 */
public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //输出当前时间
        Date date=new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dataStr = format.format(date);
        //工作内容
        System.out.println("正在进行数据库的备份工作,备份数据库的时间是:"+dataStr);
    }
}

测试调用

/**
 * @author codekiller
 * @date 2020/6/4 23:34
 */
public class HelloScheduleDemo {
    public static void main(String[] args) throws SchedulerException {
        //定时器对象
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        //定义一个工作对象 设置工作名称与组名
        JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job41","group1").build();
        //定义一个触发器 简单Trigger 设置工作名称与组名 5秒触发一次
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","group1").startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();
        //定义一个任务调度的Trigger 设置工作名称与组名 每天的24:00触发一次
        //Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1","group1").withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?")).build();
        //设置工作 与触发器
        scheduler.scheduleJob(job, trigger);
        // and start it off
        //开始定时任务
        scheduler.start();
    }
}

CornTrigger表达式的写法
* * * * * *
分别代表秒、分、时、日、月、周
例子:
0 0 12 ? * 3 每周二中午 12 点执行任务
0 0 0 0 * ? 每月 1 日 0 点执行任务
测试结果

各种触发器

常用的触发器有下面四个

  • SimpleTrigger:简单的触发器
  • CalendarIntervalTrigger:日历触发器
  • CronTrigger:Cron表达式触发器
  • DailyTimeIntervalTrigger:日期触发器

SimpleTrigger

一个quartz简单的触发器。指定从某一个时间开始,以一定的时间间隔(单位是毫秒)执行的任务。

它适合的任务类似于:9:00 开始,每隔1小时,每隔几分钟,每隔几秒钟执行一次。

它的属性有:

  • repeatInterval:重复间隔
  • repeatCount:重复次数。实际执行次数是 repeatCount+1。因为在startTime的时候一定会执行一次。
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startAt(startTime).withSchedule(SimpleScheduleBuilder.simpleSchedule()
                                     .withIntervalInSeconds(10)
                                     .withRepeatCount(5)
                                    ).build();

CalanderInteervalTrigger

类似于SimpleTrigger,指定从某一个时间开始,以一定的时间间隔执行的任务。 但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期。

相较于SimpleTrigger有两个优势:

  • 1、更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒。
  • 2、支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒。

它适合的任务类似于:9:00 开始执行,并且以后每周 9:00 执行一次

它的属性有:

  • interval:执行间隔
  • intervalUnit:执行间隔的单位(秒,分钟,小时,天,月,年,星期)
// 每两秒执行
CalendarIntervalTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(
    CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withInterval(2, 		  DateBuilder.IntervalUnit.SECOND)
).build();

DatlyTimeIntervalTrigger

指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。

它适合的任务类似于:指定每天9:00 至 18:00 ,每隔70秒执行一次,并且只要周一至周五执行。

它的属性有:

  • startTimeOfDay:每天开始时间
  • endTimeOfDay:每天结束时间
  • daysOfWeek:需要执行的星期
  • interval:执行间隔
  • intervalUnit:执行间隔的单位(秒,分钟,小时,天,月,年,星期)
  • repeatCount:重复次数
DailyTimeIntervalTrigger trigger = dailyTimeIntervalSchedule()
    .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) // 第天9:00开始
    .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(16, 0)) // 16:00 结束 
    .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) // 周一至周五执行
    .withIntervalInHours(1) // 每间隔1小时执行一次
    .withRepeatCount(100) // 最多重复100次(实际执行100+1次)
    .build();

DailyTimeIntervalTrigger trigger = dailyTimeIntervalSchedule()
    .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) // 第天9:00开始
    .endingDailyAfterCount(10) // 每天执行10次,这个方法实际上根据 startTimeOfDay+interval*count 算出 endTimeOfDay
    .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) // 周一至周五执行
    .withIntervalInHours(1) // 每间隔1小时执行一次
    .build();

// 每两秒执行
DailyTimeIntervalTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(
    DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule().withInterval(2, DateBuilder.IntervalUnit.SECOND)
).build();

CronTrigger

适合于更复杂的任务,它支持类型于Linux Cron的语法(并且更强大)。基本上它覆盖了以上三个Trigger的绝大部分能力(但不是全部)

CronTrigger 允许设定非常复杂的触发时间表。然而有时也许不得不使用两个或多个 SimpleTrigger 来满足你的触发需求,这时候你仅仅需要一个CronTrigger 实例就够了。

它的属性只有: Cron表达式,详解点击

 // 每两秒执行
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").withSchedule(
        CronScheduleBuilder.cronSchedule("/2 * * * * ?")
).build();

NthIncludedDayTrigger

org.quartz.NthIncludedDayTrigger 是 Quartz 开发团队最新加入到框架中的一个 Trigger。它设计用于在每一间隔类型的第几天执行 Job。

例如,你要在每个月的 15 号执行开票的 Job,用 NthIncludedDayTrigger 就再合适不过了。Quartz 的 Caldendar 也可与 Trigger 关联以此把周末与节假日考虑进来,并在必要时跳开这些日期。

NthIncludedDayTrigger trigger = new NthIncludedDayTrigger("MyTrigger", Scheduler.DEFAULT_GROUP);
trigger.setN(15);
trigger.setIntervalType(NthIncludedDayTrigger.INTERVAL_TYPE_MONTHLY);

Job并发控制

Job执行时,设置了间隔时间,但是有一个并发的过程。

@DisallowConcurrentExecution注解可以取消并发

@DisallowConcurrentExecution
public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //输出当前时间
        Date date=new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dataStr = format.format(date);
        //工作内容
        System.out.println("正在进行数据库的备份工作,备份数据库的时间是:"+dataStr);
    }
}

SpringBoot整合Quartz

引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

建表


DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    JOB_CLASS_NAME   VARCHAR(250) NOT NULL,
    IS_DURABLE VARCHAR(1) NOT NULL,
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    JOB_NAME  VARCHAR(200) NOT NULL,
    JOB_GROUP VARCHAR(200) NOT NULL,
    DESCRIPTION VARCHAR(250) NULL,
    NEXT_FIRE_TIME BIGINT(13) NULL,
    PREV_FIRE_TIME BIGINT(13) NULL,
    PRIORITY INTEGER NULL,
    TRIGGER_STATE VARCHAR(16) NOT NULL,
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
    START_TIME BIGINT(13) NOT NULL,
    END_TIME BIGINT(13) NULL,
    CALENDAR_NAME VARCHAR(200) NULL,
    MISFIRE_INSTR SMALLINT(2) NULL,
    JOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);

CREATE TABLE QRTZ_SIMPLE_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    REPEAT_COUNT BIGINT(7) NOT NULL,
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CRON_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    CRON_EXPRESSION VARCHAR(200) NOT NULL,
    TIME_ZONE_ID VARCHAR(80),
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (          
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    STR_PROP_1 VARCHAR(512) NULL,
    STR_PROP_2 VARCHAR(512) NULL,
    STR_PROP_3 VARCHAR(512) NULL,
    INT_PROP_1 INT NULL,
    INT_PROP_2 INT NULL,
    LONG_PROP_1 BIGINT NULL,
    LONG_PROP_2 BIGINT NULL,
    DEC_PROP_1 NUMERIC(13,4) NULL,
    DEC_PROP_2 NUMERIC(13,4) NULL,
    BOOL_PROP_1 VARCHAR(1) NULL,
    BOOL_PROP_2 VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_BLOB_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    BLOB_DATA BLOB NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_CALENDARS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    CALENDAR_NAME  VARCHAR(200) NOT NULL,
    CALENDAR BLOB NOT NULL,
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_GROUP  VARCHAR(200) NOT NULL, 
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    ENTRY_ID VARCHAR(95) NOT NULL,
    TRIGGER_NAME VARCHAR(200) NOT NULL,
    TRIGGER_GROUP VARCHAR(200) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    FIRED_TIME BIGINT(13) NOT NULL,
    SCHED_TIME BIGINT(13) NOT NULL,
    PRIORITY INTEGER NOT NULL,
    STATE VARCHAR(16) NOT NULL,
    JOB_NAME VARCHAR(200) NULL,
    JOB_GROUP VARCHAR(200) NULL,
    IS_NONCONCURRENT VARCHAR(1) NULL,
    REQUESTS_RECOVERY VARCHAR(1) NULL,
    PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);

CREATE TABLE QRTZ_SCHEDULER_STATE
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    INSTANCE_NAME VARCHAR(200) NOT NULL,
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);

CREATE TABLE QRTZ_LOCKS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    LOCK_NAME  VARCHAR(40) NOT NULL, 
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);


commit;

在这里插入图片描述

配置application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/manager?characterEncoding=UTF-8&serverTimezone=UTC
    driver-class-name: com.mysql.jdbc.Driver
  quartz:
    # 将任务等保存化到数据库
    job-store-type: jdbc
    # 程序结束时会等待quartz相关的内容结束
    wait-for-jobs-to-complete-on-shutdown: true
    # QuartzScheduler启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录
    overwrite-existing-jobs: true
    # 这里居然是个map,搞得智能提示都没有,佛了
    properties:
      org:
        quartz:
          # scheduler相关
          scheduler:
            # scheduler的实例名
            instanceName: scheduler
            instanceId: AUTO
          # 持久化相关
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            # 表示数据库中相关表是QRTZ_开头的
            tablePrefix: QRTZ_
            useProperties: false
          # 线程池相关
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            # 线程数
            threadCount: 10
            # 线程优先级
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true

周期性的定时任务

job类
@DisallowConcurrentExecution
public class Job1 extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("开始执行Job1------"+sdf.format(new Date()));
    }
}
--------------------------------------------------
@DisallowConcurrentExecution
public class Job2 extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("开始执行Job2------"+sdf.format(new Date()));
    }
}
注册定时任务
package top.codekiller.test.quartz.quartz_springboot;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author codekiller
 * @date 2020/6/5 14:40
 * @description 注册周期性的定时任务,会被持久化
 */
@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail job1Detail(){
        return JobBuilder.newJob(Job1.class).withIdentity("testJob1","testJob").storeDurably().build();
    }

    @Bean
    public Trigger testQuartzTrigger1() {
        //5秒执行一次
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();
        return TriggerBuilder.newTrigger().forJob(job1Detail())
                .withIdentity("testJob1","testJob")
                .startNow()
                .withSchedule(scheduleBuilder)
                .build();
    }

    @Bean
    public JobDetail job2Detail() {
        return JobBuilder.newJob(Job2.class).withIdentity("testJob2","testJob").storeDurably().build();
    }

    @Bean
    public Trigger testQuartzTrigger2() {
        //cron方式,每隔5秒执行一次
        return TriggerBuilder.newTrigger().forJob(job2Detail())
                .withIdentity("testJob2","testJob")
                .startNow()
                .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?"))
                .build();
    }
}
结果

无周期性的定时任务

job类
package top.codekiller.test.quartz.quartz_springboot;

import com.mchange.util.StringObjectMap;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * @author codekiller
 * @date 2020/6/5 15:28
 * @description DES
 */
@DisallowConcurrentExecution
@Slf4j
public class Job3 extends QuartzJobBean {
    @Autowired
    private Scheduler scheduler;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        Trigger trigger = jobExecutionContext.getTrigger();
        log.info("jobDetail: {}",jobDetail);
        log.info("trigger: {}",trigger);
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        log.info("username:  {};age:  {}",jobDataMap.getString("username"),jobDataMap.getInt("age"));

        // 编写任务的逻辑

        // 执行之后删除任务
        try {
            // 暂停触发器的计时
            scheduler.pauseTrigger(trigger.getKey());
            // 移除触发器中的任务
            scheduler.unscheduleJob(trigger.getKey());
            // 删除任务
            scheduler.deleteJob(jobDetail.getKey());
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}
注册定时任务
package top.codekiller.test.quartz.controller;

import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import top.codekiller.test.quartz.quartz_springboot.Job3;
import java.time.LocalDateTime;

/**
 * @author codekiller
 * @date 2020/6/5 16:14
 * @description DES
 */
@RestController
public class QuartzController {

    @Autowired
    private Scheduler scheduler;

    @GetMapping("/test")
    public ResponseEntity testQuartz() {
        //任务的cron表达式
        LocalDateTime localDateTime = LocalDateTime.now();
        String cronStr = String.format("0/5 %d %d %d %d ? %d", localDateTime.getMinute() + 1, localDateTime.getHour(), localDateTime.getDayOfMonth(), localDateTime.getMonth().getValue(), localDateTime.getYear());
        System.out.println(cronStr);
        //指定Job
        JobDetail jobDetail = JobBuilder.newJob(Job3.class).withIdentity("testJob3", "testJob")
            //添加一些参数,执行的时候用
            .usingJobData("username", "张三")
            .usingJobData("age", 18)
            .build();

        //触发器
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("testJob3", "testJob")
            .withSchedule(CronScheduleBuilder.cronSchedule(cronStr)).build();


        try {
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return ResponseEntity.ok(HttpStatus.OK.value());
    }
}
结果
执行一次后没有删除的结果

执行一次后删除的结果

在这里插入图片描述

Cron表达式详解

字段允许值允许的特殊字符
0-59, - * /
0-59, - * /
小时0-23, - * /
日期1-31, - * / L W C
月份1-12 或者 JAN-DEC, - * /
星期1-7 或者 SUN-SAT, - * / L C #
年(可选)留空, 1970-2099, - * /

如上面的表达式所示:

** * **字符被用来指定所有的值。如:”*“在分钟的字段域里表示“每分钟”。

**-**字符被用来指定一个范围。如:“10-12”在小时域意味着“10点、11点、12点”。

**,**字符被用来指定另外的值。如:“MON,WED,FRI”在星期域里表示”星期一、星期三、星期五”. 在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。

/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.

**?*只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用*表示不管星期几都会触发,实际上并不是这样。

L字符指定在月或者星期中的某天(最后一天)。即“Last ”的缩写。但是在星期和月中“L”表示不同的意思,如:在月子段中“L”指月份的最后一天-1月31日,2月28日,如果在星期字段中则简单的表示为“7”或者“SAT”。如果在星期字段中在某个value值得后面,则表示“某月的最后一个星期value”,如“6L”表示某月的最后一个星期五。

W表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。

LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

**#**字符只能用在星期字段,该字段指定了第几个星期value在某月中.例如在4#2,表示某月的第二个星期三。

每一个元素都可以显式地规定一个值(如6),一个区间(如9-12),一个列表(如9,11,13)或一个通配符(如*)。“月份中的日期”和“星期中的日期”这两个元素是互斥的,因此应该通过设置一个问号(?)来表明你不想设置的那个字段。表7.1中显示了一些cron表达式的例子和它们的意义:

表达式意义
"0 0 12 * * ?"每天中午12点触发
"0 15 10 ? * *"每天上午10:15触发
"0 15 10 * * ?"每天上午10:15触发
"0 15 10 * * ? *"每天上午10:15触发
"0 15 10 * * ? 2005"2005年的每天上午10:15触发
"0 * 14 * * ?"在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?"在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?"在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?"在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED"每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI"周一至周五的上午10:15触发
"0 15 10 15 * ?"每月15日上午10:15触发
"0 15 10 L * ?"每月最后一日的上午10:15触发
"0 15 10 ? * 6L"每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6L 2002-2005"2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3"每月的第三个星期五上午10:15触发


参考:https://segmentfault.com/a/1190000022552084

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值