[Backend] quartz creates a scheduled message sending function

Table of Contents

Preface

1. What is quartz?

2. Core concepts

1.Scheduler

2.JobDetail、Job

3.Trigger

2. Usage steps

1.pom file introduces dependencies

2. Run sql statement to create table

3. Add quartz basic configuration file

4. Create Scheduler scheduling tasks

5. Write Job to implement task execution logic

?edit

6. Delete a scheduled task

3. Commonly used methods and attributes

Summarize

Foreword

quartz is an open source task scheduling framework, often used in:

1. Overdue payment reminder for order tasks, automatic acceptance of orders

2. Regular push of messages/data

3. Scheduled generation of reports

4. Automatic updating of static data, etc.

1. What is quartz?

Introduction: quartz is an open source task scheduling framework.

Advantages: strong reliability and durability, convenience and flexibility. Also supports distributed and clustered modes

2. Core concepts

1.Scheduler

Scheduling container, all scheduling is controlled by it, the starting point of tasks

2.JobDetail、Job

JobDetail: Generally, the parameters that need to be passed are passed

Job: write the processing logic of the task

3.Trigger

Set time rules for task scheduling

2. Usage steps

1.pom file introduces dependencies

 <!--quart task scheduling dependencies-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

2. Run sql statement to create table

After introducing dependencies, the jar package has its own table creation statement. I am doing this here for persistence (to prevent scheduled tasks from being lost after the project is restarted). If you don’t have persistence requirements, you can skip this step.

Path: External Libraries → org.quartz-scheduler:quartz:2.3.2 → org → quartz → impl → jdbcjobstore → tables_mysql_innodb.sql

For convenience, I also post a sql running script here.

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(190) NOT NULL,
JOB_GROUP VARCHAR(190) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
JOB_NAME VARCHAR(190) NOT NULL,
JOB_GROUP VARCHAR(190) 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(190) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
CRON_EXPRESSION VARCHAR(120) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SIMPROP_TRIGGERS
  (
    SCHED_NAME VARCHAR(120) NOT NULL,
    TRIGGER_NAME VARCHAR(190) NOT NULL,
    TRIGGER_GROUP VARCHAR(190) 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))
ENGINE=InnoDB;

CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(190) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;

CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;

CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(190) NOT NULL,
TRIGGER_GROUP VARCHAR(190) NOT NULL,
INSTANCE_NAME VARCHAR(190) 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(190) NULL,
JOB_GROUP VARCHAR(190) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;

CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(190) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;

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

CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);

CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);

CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);

commit;

3. Add quartz basic configuration file

spring:
  quartz:
    #Related attribute configuration
    properties:
      org:
        quartz:
          scheduler:
            # The unique ID of the cluster environment. The name can be set arbitrarily. The instanceId is set to AUTO, and the system will automatically generate it for us.
            instanceName: clusteredScheduler
            instanceId: AUTO
          jobStore:
            # Very important! JDBC additions, deletions, checks and modifications are all completed by JobStore.
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            tablePrefix: QRTZ_
            isClustered: true
            clusterCheckinInterval: 10000
            useProperties: false
          threadPool:
            # Configure thread pool
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true
    #Database method
    job-store-type: jdbc
      #Initialize table structure
    #jdbc:
    #initialize-schema: never

4. Create Scheduler scheduling task

package com.example.demo.controller;

import com.example.demo.entity.TestOrderEntity;
import com.example.demo.mapper.TestOrderMapper;
import com.example.demo.quartz.MyJob;
import lombok.RequiredArgsConstructor;
import org.quartz.*;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.UUID;

/**
 * quartz test control class
 *
 * @author yooyee
 * @date 2023/10/13 14:57
 */
@RestController
@RequestMapping("/quartz")
@RequiredArgsConstructor
public class QuartzController {

    private final Scheduler scheduler;

    @PostMapping("/add")
    public String addOrder() throws SchedulerException, ParseException {

        // Generate a unique id to facilitate deletion of the corresponding scheduled task
        String orderId = UUID.randomUUID().toString().replace("-", "");
        // Specify the start time. Set a time here to send messages regularly.
        String sendTime = "2023-10-13 16:50:07";
        SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");

        //Create Job execution and pass parameters
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                .withIdentity("orderId",orderId) //Give the unique identity of this task through name and groupName
                .usingJobData("orderId",orderId) // Pass the parameters to be used
                .build();

        // Construct Trigger instance and set trigger time rules
        Trigger trigger = TriggerBuilder
                .newTrigger() // Create trigger
                .startAt(format.parse(orderEntity.getSendTime())) // Specify the start time
                .build();
        //Execute start timer
        scheduler.scheduleJob(jobDetail, trigger);
        scheduler.start();
        return "Added successfully-" + orderId;
    }
}

5. Write Job to implement task execution logic

package com.example.demo.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;

/**
 *Tasks triggered by timer
 *
 * @author yooyee
 * @date 2023/10/13 8:43
 */
public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("The logic in the MyJob timer was executed:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(jobExecutionContext.getFireTime()));
        String orderId = jobExecutionContext.getJobDetail().getJobDataMap().get("orderId").toString();
        System.out.println("Message notification with order number " + orderId + " was sent regularly");
    }
}

After the creation is successful, the scheduled task we just added can also be seen in the database. This way the tasks will not be lost when the project is restarted.

6. Delete a scheduled task

package com.example.demo.controller;

import com.example.demo.quartz.MyJob;
import lombok.RequiredArgsConstructor;
import org.quartz.*;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 * quartz test control class
 *
 * @author yooyee
 * @date 2023/10/13 14:57
 */
@RestController
@RequestMapping("/quartz")
@RequiredArgsConstructor
public class QuartzController {

    private final Scheduler scheduler;

    @GetMapping("/delete")
    public String deleteOrder(String orderId) {
        try {
            // This name and groupName are the unique identifiers created by .withIdentity("orderId", orderId) above.
            JobKey jobKey = new JobKey("orderId",orderId);
            if (!scheduler.checkExists(jobKey)) {
                System.out.println("job not exists, job name:" + orderId);
                return "job not exists, job groudName:" + orderId;
            }
            scheduler.deleteJob(jobKey);
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return "Deletion failed" + e.getMessage();
        }
        return "Delete successfully";
    }
}

3. Commonly used methods and attributes

Scheduler

.start()

Scheduler startup
.shutdown() Stop the scheduler
.standby() Scheduler’s pause
trigger .startNow() Effective immediately
.startAt(Date) Set the effective time
.endAt(Date) End trigger time
simpleTrigger .withIntervalInHours(long) Set the timer interval in hours Unit
.withIntervalInMilliseconds(long) Set the timer interval to The unit is milliseconds
.withIntervalInSeconds(long) Set the timer interval , in seconds
.withIntervalInMinutes(long) Set the timer Interval time in minutes
.withRepeatCount(int) Repeat Number of times
.repeatForever() Always repeat
JobDetail .withIdentity(“jobName”, ” jobGroup”) Set jobName and JobGroup to be unique
.usingJobData( dataMap) Pass parameters

Summary

The above is the general method of using quartz. The above example still has room for optimization, such as

1. Encapsulate JobDetail and Trigger. Control different tasks through parameters. No need to create duplicate code

2. The above only gives an example of sending notifications regularly. Once you are familiar with it, you can also try to customize CronTrigger to make time control more flexible.

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 137765 people are learning the system