Spring Boot集成Quartz动态实现数据库任务

1. Quartz简介

1.1. 什么是Quartz

Quartz是一个开源的任务调度框架。作用是基于定时、定期的策略来执行任务。
它是OpenSymphony开源组织在Job scheduling领域又一个开源项目。

“任务进度管理器”就是一个在预先被纳入日程,当时间到达时,负责执行(或者通知)其他软件组件的系统。 简单来说就是实现“计划(或定时)任务”的系统,例如:订单下单后未付款,15分钟后自动撤消订单,并自动解锁锁定的商品。

官网:http://www.quartz-scheduler.org
参考:https://github.com/dufyun/quartz-core-learning


1.2. Quartz可以用来做什么?

Quartz是一个任务调度框架。比如你遇到这样的问题:

  • 想每月11号自动提示信用卡还款金额;每月28号,信用卡自动还款。
  • 订单下单后未付款,15分钟后自动撤消订单,并自动解锁锁定的商品。
  • 想每年4月1日自己给当年暗恋女神发一封匿名贺卡。
  • 想每隔1小时,备份一下自己的爱情动作片、学习笔记到云盘。
  • 医院系统11点才能开放挂号。
  • 企业中如每天凌晨2点触发数据同步、发送Email等操作。
  • ……
    这些问题总结起来就是:在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活。

1.3. 同类型框架有哪些?

  • TimeTask: 在Quartz前还是显得过于简单、不完善,不能直接满足开发者的较为复杂的应用场景。
  • Elastic-Job: 当当网推出的分布式定时任务框架。
  • TBSchedule: Alibaba开发的分布式定时任务框架。

2. Spring Boot集成Quartz动态实现数据库任务


2.1. 搭建Spring Boot工程


2.2. 引入Quartz依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-quartzartifactId>
dependency>

2.3. 添加注解

在主程序类上加@EnableScheduling开启定时任务注解。

@SpringBootApplication
@MapperScan("com.example.mapper")
@EnableSwagger2
@EnableScheduling
public class SPApplication {
    public static void main(String[] args) {
        SpringApplication.run(SPApplication.class, args);
    }
}

2.4. 添加Quartz配置文件

在application.yml的spring下添加:

quartz:
  #相关属性配置
  properties:
    org:
      quartz:
        scheduler:
          instanceName: DefaultQuartzScheduler
          instanceId: AUTO
        jobStore:
          class: org.quartz.impl.jdbcjobstore.JobStoreTX
          driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
          tablePrefix: QRTZ_
          isClustered: false
          clusterCheckinInterval: 10000
          useProperties: true
        threadPool:
          class: org.quartz.simpl.SimpleThreadPool
          threadCount: 10
          threadPriority: 5
          threadsInheritContextClassLoaderOfInitializingThread: true
  #数据库方式
  job-store-type: jdbc
  #当spring关闭时,会等待所有已经启动的quartz job结束后spring才能完全shutdown
  wait-for-jobs-to-complete-on-shutdown: true

2.5. 创建job类

任务一:

public class QMJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("任务一....");
    }
}

任务二:

public class YRJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("任务二....");
    }
}

2.6. 创建Quartz需要的数据库表

项目中Quartz的数据库表由两部分组成:
第一部分:Quartz自带的11张表。
第二部分:项目中需要的任务记录表、任务参数表。
Spring Boot集成Quartz动态实现数据库任务_第1张图片

2.6.1. 创建Quartz自带的11张表

第一步:进入Quartz的官网: http://www.quartz-scheduler.org/,点击“Downloads”。
Spring Boot集成Quartz动态实现数据库任务_第2张图片
在“Downloads”页面下载相应的压缩包文件。

第二步:对下载的压缩包文件进行解压。
在这里插入图片描述
第三步:执行SQL脚本
在解压目录\src\org\quartz\impl\jdbcjobstore下有常用数据库创建Quartz表的脚本:
Spring Boot集成Quartz动态实现数据库任务_第3张图片
根据项目使用的数据库软件,选择相应的.sql脚本执行。比如:MySQL数据库就使用tables_mysql.sql
将tables_mysql.sql导入运行,在数据库中生成11张表,如下:
Spring Boot集成Quartz动态实现数据库任务_第4张图片

2.6.2. 创建项目中需要的任务记录表、任务参数表

需要两张业务表:
Id
Job_name
Job_group
Job_class
Job_descript
Job_cron
Job_status
Add_time
Update_time

爬取表:
Id
Job_id
Request_time
Job_data

第一步:创建任务记录表,并添加两条测试数据
在这里插入图片描述
Class c = Class.forName(“com.manubao.quartz.MyJob”)

任务记录表t_schedule_trigger:

#创建任务记录表
CREATE TABLE `t_schedule_trigger`(
	`id` INT PRIMARY KEY AUTO_INCREMENT,		#主键,标识列
	`job_name` VARCHAR(100) NOT NULL UNIQUE,	#任务名称
	`job_group` VARCHAR(50) NOT NULL,			#任务分组名称
	`job_class` VARCHAR(200) NOT NULL,			#任务类:填写Job类的完整类名
	`job_desc` VARCHAR(200) NOT NULL,			#任务描述
	`cron` VARCHAR(100) NOT NULL,				#Cron表达式
	`trigger_name` VARCHAR(100) NOT NULL UNIQUE ,	#触发器名称
	`trigger_group` VARCHAR(50) NOT NULL,		#触发器分组名称
	`trigger_desc` VARCHAR(200) NOT NULL,		#触发器描述
	`status` CHAR(1) NOT NULL,					#状态:0禁用 1启用
	`account` INT NOT NULL,					#添加人:这里需要与用户表建立主外键关系
	`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP	#添加时间
)ENGINE=INNODB DEFAULT CHARSET=utf8;

#添加数据
insert into t_schedule_trigger(
job_name, job_group, job_class, job_desc, cron, trigger_name, trigger_group, trigger_desc, status, account
) values
('愚人节的问候', '愚人组' , 'com.manubao.quartz.YRJob', '愚人节发个ILOVEYOU', '*/5 * * * * *', '愚人节触发器', 'trigger1', '触发器描述', 1, 1),
('中秋节的问候', '中秋组' , 'com.manubao.quartz.QmJob', '中秋节发个IMISSYOU', '*/7 * * * * *', '中秋节触发器', 'trigger1', '中秋节描述', 1, 1);

第二步:创建任务中的参数表(暂时不用)

#创建任务参数表
create table `t_schedule_trigger_param`(
	`id` int primary key auto_increment,					# ID
	`name` varchar(200) not null,							#参数名
	`value` varchar(512),								#参数值
	`st_id` int not null references t_schedule_trigger(id)		#外键:引用t_schedule_trigger(id)
);

2.7. 创建任务记录表实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_schedule_trigger")
public class Trigger {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;             //主键,标识列
    private String jobName;        //任务名称
    private String jobGroup;       //任务分组名称
    private String jobClass;       //任务类:填写Job类的完整类名
    private String jobDesc;        //任务描述
    private String cron;            //Cron表达式
    private String triggerName;    //触发器名称
    private String triggerGroup;   //触发器分组名称
    private String triggerDesc;    //触发器描述
    private int status;             //状态:0禁用 1启用
    private int account;            //添加人
    private Date createTime;       //添加时间
}

2.8. Dao层接口

@Mapper
public interface QuartzMapper extends BaseMapper<Trigger> {
}

2.9. Service层接口及实现类

接口:

public interface QuartzService extends IService<Trigger> {
    //更新任务
    void refreshTrigger();
}

实现类:

import javax.annotation.Resource;
import java.util.List;

@Service
public class QuartzServiceImpl extends ServiceImpl<QuartzMapper, Trigger> implements QuartzService {

    @Resource
    private QuartzMapper quartzMapper;

    @Autowired
    private Scheduler scheduler;

    @Override
    public void refreshTrigger() {
        //获得所有的任务
        List<Trigger> triggers = quartzMapper.selectList(null);


        if( triggers != null){  //数据库中存在任务
            for (Trigger trigger1 : triggers) {
                //System.out.println(trigger);

                if(trigger1.getStatus() == 1) {  //1表示正常启用

                    //拿出一个任务,启动一个任务
                    try {
                        //1.定义JobDetail,将HelloJob类添加到JobDetail对象中(添加到Job清单)
                        //com.example.job.YRJob
                        JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(trigger1.getJobClass()))
                                //任务的名字和组的名字(坑)
                                //任务名字不能相同
                                .withIdentity(trigger1.getJobName(), trigger1.getJobGroup())
                                .build();

                        //2.定义Trigger触发器,使用简单触发器,设置name/group
                        org.quartz.Trigger trigger = TriggerBuilder.newTrigger()
                                .withIdentity(trigger1.getTriggerName(), trigger1.getTriggerGroup())
                                .startNow()
                                .withSchedule(CronScheduleBuilder.cronSchedule(trigger1.getCron()))
                                .build();

                        //3.创建scheduler调度器
                        scheduler.scheduleJob(jobDetail, trigger);
                        //启动调度器
                        scheduler.start();

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }
        }

    }
}

你可能感兴趣的:(java,quartz)