精彩回顾我们在spring boot quartz定时任务基本使用及介绍和spring boot quartz持久化存储分别对quartz基本信息及持久化存储进行了介绍。这篇文章我们继续介绍给予持久化存储实现任务的动态管理。创建表结构为了存储我们自己动态创建的任务，除了spring boot quartz持久化存储介绍的添加quartz表结构之外，我们还需要添加一个自己的表。以下是MySQL的表结构，其他类型的数据库请按需修改。/* Navicat Premium Data Transfer Source Server : localhost Source Server Type : MySQL Source Server Version : 80021 Source Host : localhost:3306 Source Schema : quartz Target Server Type : MySQL Target Server Version : 80021 File Encoding : 65001 Date: 30/09/2020 13:34:24 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for task_quartz -- ---------------------------- DROP TABLE IF EXISTS `task_quartz`; CREATE TABLE `task_quartz` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `job_group` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务分组', `job_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务名', `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务描述', `cron_expression` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'cron表达式', `job_class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务执行时调用哪个类的方法 包名+类名', `job_status` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1' COMMENT '任务状态', `create_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '创建者', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', `modify_by` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '更新者', `modify_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `NameWithGroup`(`job_group`, `job_name`) USING BTREE COMMENT '任务及分组唯一' ) ENGINE = MyISAM AUTO_INCREMENT = 68 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1; 创建工程，添加依赖如果要实现任务的动态管理，这里单独借助一张表，存储任务的信息。先介绍一个依赖的情况：MySQL数据库mybatis执行sqlquartz依赖lombok具体项目依赖如下： <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>修改配置文件application.yamlserver: port: 8080 spring: profiles: active: devapplication-dev.yamlspring: datasource: url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&&serverTimezone=UTC username: root password: root type: com.zaxxer.hikari.HikariDataSource quartz: job-store-type: jdbc mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: cc.lisen.quartztask.entity configuration: map-underscore-to-camel-case: true 主要配置信息：MySQL数据库连接mybatis配置job-store-type存储到数据库增加mybatis相关操作TaskQuartzMapper.xml<?xml version="1.0" encoding="UTF-8"?> <mapper namespace="cc.lisen.quartztask.mapper.TaskQuartzMapper"> <resultMap id="BaseResultMap" type="cc.lisen.quartztask.entity.TaskQuartz"> <id column="id" jdbcType="BIGINT" property="id"/> <result column="job_group" jdbcType="VARCHAR" property="jobGroup"/> <result column="job_name" jdbcType="VARCHAR" property="jobName"/> <result column="description" jdbcType="VARCHAR" property="description"/> <result column="cron_expression" jdbcType="VARCHAR" property="cronExpression"/> <result column="job_class_name" jdbcType="VARCHAR" property="jobClassName"/> <result column="job_status" jdbcType="VARCHAR" property="jobStatus"/> <result column="create_by" jdbcType="VARCHAR" property="createBy"/> <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/> <result column="modify_by" jdbcType="VARCHAR" property="modifyBy"/> <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/> </resultMap> <sql id="Base_Column_List"> id, job_group, job_name, description, cron_expression, job_class_name, job_status, create_by, create_time, modify_by, modify_time </sql> select <include refid="Base_Column_List"/> from task_quartz where id = #{id,jdbcType=BIGINT} select <include refid="Base_Column_List"/> from task_quartz where job_name = #{jonName,jdbcType=VARCHAR} and job_group = #{jobGroup,jdbcType=VARCHAR} <delete id="deleteByPrimaryKey" parameterType="java.lang.Long"> delete from task_quartz where id = #{id,jdbcType=BIGINT} </delete> <delete id="deleteByJobNameAndJobGroup"> delete from task_quartz where job_name = #{jonName,jdbcType=VARCHAR} and job_group = #{jobGroup,jdbcType=VARCHAR} </delete> <insert id="insert" keyColumn="id" keyProperty="id" parameterType="cc.lisen.quartztask.entity.TaskQuartz" useGeneratedKeys="true"> insert into task_quartz (job_group, job_name, description, cron_expression, job_class_name, job_status, create_by, create_time, modify_by, modify_time) values (#{jobGroup,jdbcType=VARCHAR}, #{jobName,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, #{cronExpression,jdbcType=VARCHAR}, #{jobClassName,jdbcType=VARCHAR}, #{jobStatus,jdbcType=VARCHAR}, #{createBy,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifyBy,jdbcType=VARCHAR}, #{modifyTime,jdbcType=TIMESTAMP}) </insert> <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="cc.lisen.quartztask.entity.TaskQuartz" useGeneratedKeys="true"> insert into task_quartz <trim prefix="(" suffix=")" suffixOverrides=","> <if test="jobGroup != null"> job_group, </if> <if test="jobName != null"> job_name, </if> <if test="description != null"> description, </if> <if test="cronExpression != null"> cron_expression, </if> <if test="jobClassName != null"> job_class_name, </if> <if test="jobStatus != null"> job_status, </if> <if test="createBy != null"> create_by, </if> <if test="createTime != null"> create_time, </if> <if test="modifyBy != null"> modify_by, </if> <if test="modifyTime != null"> modify_time, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="jobGroup != null"> #{jobGroup,jdbcType=VARCHAR}, </if> <if test="jobName != null"> #{jobName,jdbcType=VARCHAR}, </if> <if test="description != null"> #{description,jdbcType=VARCHAR}, </if> <if test="cronExpression != null"> #{cronExpression,jdbcType=VARCHAR}, </if> <if test="jobClassName != null"> #{jobClassName,jdbcType=VARCHAR}, </if> <if test="jobStatus != null"> #{jobStatus,jdbcType=VARCHAR}, </if> <if test="createBy != null"> #{createBy,jdbcType=VARCHAR}, </if> <if test="createTime != null"> #{createTime,jdbcType=TIMESTAMP}, </if> <if test="modifyBy != null"> #{modifyBy,jdbcType=VARCHAR}, </if> <if test="modifyTime != null"> #{modifyTime,jdbcType=TIMESTAMP}, </if> </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="cc.lisen.quartztask.entity.TaskQuartz"> update task_quartz <set> <if test="jobGroup != null"> job_group = #{jobGroup,jdbcType=VARCHAR}, </if> <if test="jobName != null"> job_name = #{jobName,jdbcType=VARCHAR}, </if> <if test="description != null"> description = #{description,jdbcType=VARCHAR}, </if> <if test="cronExpression != null"> cron_expression = #{cronExpression,jdbcType=VARCHAR}, </if> <if test="jobClassName != null"> job_class_name = #{jobClassName,jdbcType=VARCHAR}, </if> <if test="jobStatus != null"> job_status = #{jobStatus,jdbcType=VARCHAR}, </if> <if test="createBy != null"> create_by = #{createBy,jdbcType=VARCHAR}, </if> <if test="createTime != null"> create_time = #{createTime,jdbcType=TIMESTAMP}, </if> <if test="modifyBy != null"> modify_by = #{modifyBy,jdbcType=VARCHAR}, </if> <if test="modifyTime != null"> modify_time = #{modifyTime,jdbcType=TIMESTAMP}, </if> </set> where id = #{id,jdbcType=BIGINT} </update> <update id="updateByPrimaryKey" parameterType="cc.lisen.quartztask.entity.TaskQuartz"> update task_quartz set job_group = #{jobGroup,jdbcType=VARCHAR}, job_name = #{jobName,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR}, cron_expression = #{cronExpression,jdbcType=VARCHAR}, job_class_name = #{jobClassName,jdbcType=VARCHAR}, job_status = #{jobStatus,jdbcType=VARCHAR}, create_by = #{createBy,jdbcType=VARCHAR}, create_time = #{createTime,jdbcType=TIMESTAMP}, modify_by = #{modifyBy,jdbcType=VARCHAR}, modify_time = #{modifyTime,jdbcType=TIMESTAMP} where id = #{id,jdbcType=BIGINT} </update> </mapper>TaskQuartz.java/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.cc */ @Data public class TaskQuartz implements Serializable { private Long id; /** * 任务分组 */ private String jobGroup; /** * 任务名 */ private String jobName; /** * 任务描述 */ private String description; /** * cron表达式 */ private String cronExpression; /** * 任务执行时调用哪个类的方法 包名+类名 */ private String jobClassName; /** * 任务状态 */ private String jobStatus; /** * 创建者 */ private String createBy; /** * 创建时间 */ private Date createTime; /** * 更新者 */ private String modifyBy; /** * 更新时间 */ private Date modifyTime; private static final long serialVersionUID = 1L; }TaskQuartzService.java/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.cc */ public interface TaskQuartzService { /** * 根据主键删除 * @param id 主键 * @return 删除行数 */ int deleteByPrimaryKey(Long id); /** * 插入 * @param record 实体 * @return 成功返回1 */ int insert(TaskQuartz record); /** * 插入修改的值 * @param record 实体 * @return 成功返回1 */ int insertSelective(TaskQuartz record); /** * 根据主键获取 * @param id 主键 * @return 实体 */ TaskQuartz selectByPrimaryKey(Long id); /** * 更新 * @param record 实体 * @return 更新成功返回1 */ int updateByPrimaryKeySelective(TaskQuartz record); /** * 更新所有值 * @param record 实体 * @return 成功返回1 */ int updateByPrimaryKey(TaskQuartz record); /** * 根据名称及分组查找 * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ TaskQuartz selectByJobNameAndJobGroup(@Param("jonName") String jobName, @Param("jobGroup") String jobGroup); /** * 根据名称及分组查找 * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ int deleteByJobNameAndJobGroup(@Param("jonName") String jobName,@Param("jobGroup") String jobGroup); }TaskQuartzServiceImpl.java/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.cc */ @Service public class TaskQuartzServiceImpl implements TaskQuartzService { @Resource TaskQuartzMapper taskQuartzMapper; /** * 根据主键删除 * * @param id 主键 * @return 删除行数 */ @Override public int deleteByPrimaryKey(Long id) { return taskQuartzMapper.deleteByPrimaryKey(id); } /** * 插入 * * @param record 实体 * @return 成功返回1 */ @Override public int insert(TaskQuartz record) { return taskQuartzMapper.insert(record); } /** * 插入修改的值 * * @param record 实体 * @return 成功返回1 */ @Override public int insertSelective(TaskQuartz record) { return taskQuartzMapper.insertSelective(record); } /** * 根据主键获取 * * @param id 主键 * @return 实体 */ @Override public TaskQuartz selectByPrimaryKey(Long id) { return taskQuartzMapper.selectByPrimaryKey(id); } /** * 更新 * * @param record 实体 * @return 更新成功返回1 */ @Override public int updateByPrimaryKeySelective(TaskQuartz record) { return taskQuartzMapper.updateByPrimaryKeySelective(record); } /** * 更新所有值 * * @param record 实体 * @return 成功返回1 */ @Override public int updateByPrimaryKey(TaskQuartz record) { return taskQuartzMapper.updateByPrimaryKey(record); } /** * 根据名称及分组查找 * * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ @Override public TaskQuartz selectByJobNameAndJobGroup(String jobName, String jobGroup) { return taskQuartzMapper.selectByJobNameAndJobGroup(jobName,jobGroup); } /** * 根据名称及分组查找 * * @param jobName 任务名称 * @param jobGroup 任务分组 * @return 任务 */ @Override public int deleteByJobNameAndJobGroup(String jobName, String jobGroup) { return taskQuartzMapper.deleteByJobNameAndJobGroup(jobName,jobGroup); } } 增加测试任务PrintJob.java/** * @author laughing * @date 2020/9/30 * @site https://www.lisen.cc */ public class PrintJob implements Job { private final Logger logger = LoggerFactory.getLogger(PrintJob.class); /** * 执行任务 * * @param jobExecutionContext * @throws JobExecutionException */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { try { logger.info("Hello Job执行时间: " + new Date() + " Blog:" + jobExecutionContext.getJobDetail().getJobDataMap().get("blog")); Thread.sleep(1000 * 5); System.out.println("================执行完成========================"); } catch (Exception e) { e.printStackTrace(); } } }测试新增任务新增任务时，我们并没有创建quartz相关表，只是存储到task_quartz表中，任务启动时，插入quartz表 /** * 新增或者保存任务 * 任务只是存储到task_quartz表中，任务启动时，插入quartz表 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("saveQuartz") public Result save(@RequestBody TaskQuartz taskQuartz) { TaskQuartz task = taskQuartzService.selectByJobNameAndJobGroup(taskQuartz.getJobName(), taskQuartz.getJobGroup()); if (task == null) { task = new TaskQuartz(); BeanUtils.copyProperties(taskQuartz, task); taskQuartzService.insertSelective(task); } else { taskQuartzService.updateByPrimaryKeySelective(taskQuartz); } return Result.ok(); }测试启动任务任务启动时，启动任务时，将任务信息持久化到quartz表中/** * 启用任务 * 启动任务时，将任务信息持久化到quartz表中 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("startJob") public Result startJob(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz); // 存在先删除 if (scheduler.checkExists(jobKey)) { scheduler.deleteJob(jobKey); } Class classz = Class.forName(taskQuartz.getJobClassName()); JobDetail jobDetail = JobBuilder.newJob() .withDescription(taskQuartz.getDescription()) .withIdentity(jobKey) .usingJobData("blog", "https://lisen.cc") .ofType(classz).build(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("Trigger_" + taskQuartz.getJobName(), "TriggerGroup_" + taskQuartz.getJobGroup()) .withSchedule(CronScheduleBuilder.cronSchedule(taskQuartz.getCronExpression())) .startNow() .build(); scheduler.scheduleJob(jobDetail, trigger); } catch (Exception exception) { return Result.error(exception.getMessage()); } return Result.ok(); }通过postman测试，我们可以观察控制台，任务时10s执行一次暂停任务/** * 暂停任务 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("shutdown") public Result shutdown(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz); scheduler.pauseJob(jobKey); return Result.ok(); } catch (Exception ex) { return Result.error(ex.getMessage()); } }恢复任务 /** * 恢复任务 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("resumeJob") public Result resumeJob(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz); scheduler.resumeJob(jobKey); return Result.ok(); } catch (Exception ex) { return Result.error(ex.getMessage()); } }删除任务/** * 删除任务 * * @param taskQuartz 实体 * @return 结果 */ @RequestMapping("removeJob") public Result removeJob(@RequestBody TaskQuartz taskQuartz) { try { JobKey jobKey = getJobKeyByTaskQuartz(taskQuartz); scheduler.deleteJob(jobKey); taskQuartzService.deleteByJobNameAndJobGroup(taskQuartz.getJobName(),taskQuartz.getJobGroup()); return Result.ok(); } catch (Exception ex) { return Result.error(ex.getMessage()); } }
在spring boot quartz定时任务基本使用及介绍的博文中，我们简单介绍了quartz的基础概念及简单的使用，细心的童鞋可以发现，那个demo虽然能用，但是存在一个问题：一旦应用停止，计划任务变失效了。如何解决应用停止或者重启不会丢失计划任务信息，便是我们这篇博文要讨论的问题。Quartz提供两种基本作业存储类型：RAMJobStore ：RAM也就是内存，默认情况下Quartz会将任务调度存在内存中，这种方式性能是最好的，因为内存的速度是最快的。不好的地方就是数据缺乏持久性，但程序崩溃或者重新发布的时候，所有运行信息都会丢失。JDBC作业存储：存到数据库之后，可以做单点也可以做集群，当任务多了之后，可以统一进行管理。关闭或者重启服务器，运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢。Quartz初始化表MySQL# # Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar # # PLEASE consider using mysql with innodb tables to avoid locking issues # # In your Quartz properties file, you'll need to set # org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate # 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; Oracle-- -- A hint submitted by a user: Oracle DB MUST be created as "shared" and the -- job_queue_processes parameter must be greater than 2 -- However, these settings are pretty much standard after any -- Oracle install, so most users need not worry about this. -- -- Many other users (including the primary author of Quartz) have had success -- runing in dedicated mode, so only consider the above as a hint ;-) -- delete from qrtz_fired_triggers; delete from qrtz_simple_triggers; delete from qrtz_simprop_triggers; delete from qrtz_cron_triggers; delete from qrtz_blob_triggers; delete from qrtz_triggers; delete from qrtz_job_details; delete from qrtz_calendars; delete from qrtz_paused_trigger_grps; delete from qrtz_locks; delete from qrtz_scheduler_state; drop table qrtz_calendars; drop table qrtz_fired_triggers; drop table qrtz_blob_triggers; drop table qrtz_cron_triggers; drop table qrtz_simple_triggers; drop table qrtz_simprop_triggers; drop table qrtz_triggers; drop table qrtz_job_details; drop table qrtz_paused_trigger_grps; drop table qrtz_locks; drop table qrtz_scheduler_state; CREATE TABLE qrtz_job_details ( SCHED_NAME VARCHAR2(120) NOT NULL, JOB_NAME VARCHAR2(200) NOT NULL, JOB_GROUP VARCHAR2(200) NOT NULL, DESCRIPTION VARCHAR2(250) NULL, JOB_CLASS_NAME VARCHAR2(250) NOT NULL, IS_DURABLE VARCHAR2(1) NOT NULL, IS_NONCONCURRENT VARCHAR2(1) NOT NULL, IS_UPDATE_DATA VARCHAR2(1) NOT NULL, REQUESTS_RECOVERY VARCHAR2(1) NOT NULL, JOB_DATA BLOB NULL, CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) ); CREATE TABLE qrtz_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, JOB_NAME VARCHAR2(200) NOT NULL, JOB_GROUP VARCHAR2(200) NOT NULL, DESCRIPTION VARCHAR2(250) NULL, NEXT_FIRE_TIME NUMBER(13) NULL, PREV_FIRE_TIME NUMBER(13) NULL, PRIORITY NUMBER(13) NULL, TRIGGER_STATE VARCHAR2(16) NOT NULL, TRIGGER_TYPE VARCHAR2(8) NOT NULL, START_TIME NUMBER(13) NOT NULL, END_TIME NUMBER(13) NULL, CALENDAR_NAME VARCHAR2(200) NULL, MISFIRE_INSTR NUMBER(2) NULL, JOB_DATA BLOB NULL, CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK 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 VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, REPEAT_COUNT NUMBER(7) NOT NULL, REPEAT_INTERVAL NUMBER(12) NOT NULL, TIMES_TRIGGERED NUMBER(10) NOT NULL, CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_cron_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, CRON_EXPRESSION VARCHAR2(120) NOT NULL, TIME_ZONE_ID VARCHAR2(80), CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_simprop_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, STR_PROP_1 VARCHAR2(512) NULL, STR_PROP_2 VARCHAR2(512) NULL, STR_PROP_3 VARCHAR2(512) NULL, INT_PROP_1 NUMBER(10) NULL, INT_PROP_2 NUMBER(10) NULL, LONG_PROP_1 NUMBER(13) NULL, LONG_PROP_2 NUMBER(13) NULL, DEC_PROP_1 NUMERIC(13,4) NULL, DEC_PROP_2 NUMERIC(13,4) NULL, BOOL_PROP_1 VARCHAR2(1) NULL, BOOL_PROP_2 VARCHAR2(1) NULL, CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_blob_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, BLOB_DATA BLOB NULL, CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_calendars ( SCHED_NAME VARCHAR2(120) NOT NULL, CALENDAR_NAME VARCHAR2(200) NOT NULL, CALENDAR BLOB NOT NULL, CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) ); CREATE TABLE qrtz_paused_trigger_grps ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_fired_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, ENTRY_ID VARCHAR2(95) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, INSTANCE_NAME VARCHAR2(200) NOT NULL, FIRED_TIME NUMBER(13) NOT NULL, SCHED_TIME NUMBER(13) NOT NULL, PRIORITY NUMBER(13) NOT NULL, STATE VARCHAR2(16) NOT NULL, JOB_NAME VARCHAR2(200) NULL, JOB_GROUP VARCHAR2(200) NULL, IS_NONCONCURRENT VARCHAR2(1) NULL, REQUESTS_RECOVERY VARCHAR2(1) NULL, CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID) ); CREATE TABLE qrtz_scheduler_state ( SCHED_NAME VARCHAR2(120) NOT NULL, INSTANCE_NAME VARCHAR2(200) NOT NULL, LAST_CHECKIN_TIME NUMBER(13) NOT NULL, CHECKIN_INTERVAL NUMBER(13) NOT NULL, CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) ); CREATE TABLE qrtz_locks ( SCHED_NAME VARCHAR2(120) NOT NULL, LOCK_NAME VARCHAR2(40) NOT NULL, CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME) ); 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); postgresql-- Thanks to Patrick Lightbody for submitting this... -- -- In your Quartz properties file, you'll need to set -- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate DROP TABLE IF EXISTS qrtz_fired_trigger`s; 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_cron_triggers; DROP TABLE IF EXISTS qrtz_simprop_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 BOOL NOT NULL, IS_NONCONCURRENT BOOL NOT NULL, IS_UPDATE_DATA BOOL NOT NULL, REQUESTS_RECOVERY BOOL NOT NULL, JOB_DATA BYTEA 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 NULL, PREV_FIRE_TIME BIGINT NULL, PRIORITY INTEGER NULL, TRIGGER_STATE VARCHAR(16) NOT NULL, TRIGGER_TYPE VARCHAR(8) NOT NULL, START_TIME BIGINT NOT NULL, END_TIME BIGINT NULL, CALENDAR_NAME VARCHAR(200) NULL, MISFIRE_INSTR SMALLINT NULL, JOB_DATA BYTEA 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 NOT NULL, REPEAT_INTERVAL BIGINT NOT NULL, TIMES_TRIGGERED BIGINT 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(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) ); 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 BOOL NULL, BOOL_PROP_2 BOOL 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 BYTEA 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 BYTEA 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 NOT NULL, SCHED_TIME BIGINT NOT NULL, PRIORITY INTEGER NOT NULL, STATE VARCHAR(16) NOT NULL, JOB_NAME VARCHAR(200) NULL, JOB_GROUP VARCHAR(200) NULL, IS_NONCONCURRENT BOOL NULL, REQUESTS_RECOVERY BOOL 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 NOT NULL, CHECKIN_INTERVAL BIGINT 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) ); 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; 其余的配置文件，大家可以去官网下载配置依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency>配置文件quartz.properties###################jdbcJobStore############################ org.quartz.scheduler.instanceName=MyScheduler org.quartz.scheduler.instanceId=AUTO org.quartz.threadPool.threadCount=3 # 所有的quartz数据例如job和Trigger的细节信息被保存在内存或数据库中,有两种实现：JobStoreTX(自己管理事务) #和JobStoreCMT（application server管理事务，即全局事务JTA） org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX # 类似于Hibernate的dialect，用于处理DB之间的差异，StdJDBCDelegate能满足大部分的DB org.quartz.jobStore.driverDelegateClass =org.quartz.impl.jdbcjobstore.StdJDBCDelegate #数据库表的前缀 org.quartz.jobStore.tablePrefix=QRTZ_ #配置数据源的名称 org.quartz.jobStore.dataSource=myDS #为了指示JDBCJobStore所有的JobDataMaps中的值都是字符串，并且能以“名字-值”对的方式存储而不是以复杂对象的序列化形式存储在BLOB字段中，应该设置为true(缺省方式) org.quartz.jobStore.useProperties = true # 检入到数据库中的频率(毫秒)。检查是否其他的实例到了应当检入的时候未检入这能指出一个失败的实例， #且当前Scheduler会以此来接管执行失败并可恢复的Job通过检入操作，Scheduler也会更新自身的状态记录 org.quartz.jobStore.clusterCheckinInterval=20000 # 是否集群、负载均衡、容错，如果应用在集群中设置为false会出错 org.quartz.jobStore.isClustered=false #misfire时间设置 org.quartz.jobStore.misfireThreshold=60000 # 连接超时重试连接的间隔。使用 RamJobStore时，该参数并没什么用【默认15000】【非必须】 #org.quartz.scheduler.dbFailureRetryInterval = 15000 #下面是数据库链接相关的配置 org.quartz.dataSource.myDS.driver=com.mysql.jdbc.Driver org.quartz.dataSource.myDS.URL=jdbc:mysql://localhost:3306/quartz?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC org.quartz.dataSource.myDS.user=root org.quartz.dataSource.myDS.password=root org.quartz.dataSource.myDS.maxConnections=5 使用定义Job类package org.lisen.quartzjdbc.scheduler; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.SimpleDateFormat; import java.util.Date; /** * @author laughing * @date 2020/9/29 * @site https://www.lisen.cc */ public class PrintService implements Job { private final Logger logger = LoggerFactory.getLogger(PrintService.class); /** * 执行 * @param jobExecutionContext * @throws JobExecutionException */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); } } 创建计划任务/** * @author laughing * @date 2020/9/29 * @site https://www.lisen.cc */ @RestController public class QuartzController { @RequestMapping("/quartzJdbc") public String quartzJdbc() throws SchedulerException { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger","triGroup") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) .withRepeatCount(0)) .build(); JobDetail job = JobBuilder.newJob(PrintService.class) .usingJobData("JobKey","JobValue") .withIdentity("Job","JobGroup") .withDescription("打印任务") .build(); scheduler.scheduleJob(job, trigger); scheduler.pauseAll(); return "success"; } }
什么是QuartzQuartz是一个完全由java编写的开源作业调度框架，由OpenSymphony组织开源出来。所谓作业调度其实就是按照程序的设定，某一时刻或者时间间隔去执行某个代码。最常用的就是报表的制作了。Quartz基本使用添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>创建Job/** * @author laughing * @date 2020/9/29 * @site https://www.lisen.org */ public class PrintJobService implements Job { private final Logger logger = LoggerFactory.getLogger(PrintJobService.class); /** * 任务执行 * * @param jobExecutionContext 任务执行信息 */ @Override public void execute(JobExecutionContext jobExecutionContext) { logger.info("准备获取scheduler参数"); try { String schedulerValue = jobExecutionContext.getScheduler().getContext().getString("sKey"); logger.info(schedulerValue); } catch (SchedulerException e) { e.printStackTrace(); } logger.info("完成获取scheduler参数\n"); logger.info("准备获取TriggerData"); JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap(); for (String triggerKey : triggerDataMap.getKeys()) { logger.info(triggerDataMap.getString(triggerKey)); } logger.info("完成获取TriggerData\n"); logger.info("准备获取JobData"); JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); for (String triggerKey : jobDataMap.getKeys()) { logger.info(jobDataMap.getString(triggerKey)); } logger.info("完成获取JobData"); } }使用/** * @author laughing * @date 2020/9/29 * @site https://www.lisen.org */ @RestController public class QuartzController { @RequestMapping("/quartz") public String quartz() throws SchedulerException { //创建一个scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); //通过scheduler传参数 scheduler.getContext().put("sKey", "sValue"); //创建一个Trigger Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .usingJobData("t1", "tv1") //3秒执行一次 .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3) //执行1次 .withRepeatCount(0)) .build(); trigger.getJobDataMap().put("t2", "tv2"); //创建一个job JobDetail job = JobBuilder.newJob(PrintJobService.class) .usingJobData("j1", "jv1") .withIdentity("myJob", "myGroup").build(); job.getJobDataMap().put("j2", "jv2"); //注册trigger并启动scheduler scheduler.scheduleJob(job, trigger); scheduler.start(); return "success"; } }Quartz的基本组成一、调度器（Scheduler)调度器用来管理触发器和作业。Trigger和JobDetail可以注册到Scheduler中，两者在Scheduler中都拥有自己的唯一的组和名称用来进行彼此的区分，Scheduler可以通过组名或者名称来对Trigger和JobDetail来进行管理。一个Trigger只能对应一个Job，但是一个Job可以对应多个Trigger。每个Scheduler都包含一个SchedulerContext，用来保存Scheduler的上下文。Job和Trigger都可以获取SchedulerContext中的信息。Scheduler包含两个重要的组件，JobStore和ThreadPool。JobStore用来存储运行时信息，包括Trigger,Schduler,JobDetail，业务锁等。它有多种实现RAMJob(内存实现)，JobStoreTX(JDBC，事务由Quartz管理）等。ThreadPool就是线程池，Quartz有自己的线程池实现。所有任务的都会由线程池执行。Scheduler是由SchdulerFactory创建，它有两个实现：DirectSchedulerFactory和StdSchdulerFactory。前者可以用来在代码里定制你自己的Schduler参数。后者是直接读取classpath下的quartz.properties（不存在就都使用默认值）配置来实例化Schduler。通常来讲，我们使用StdSchdulerFactory也就足够了二、触发器（Trigger）Trigger是用来定义Job的执行规则，直白的说就是什么时间、重复多少次。主要有四种触发器，其中SimpleTrigger和CronTrigger触发器用的最多。SimpleTrigger从某一个时间开始，以一定的时间间隔来执行任务。它主要有两个属性，repeatInterval 重复的时间间隔；repeatCount重复的次数，实际上执行的次数是n+1,因为在startTime的时候会执行一次。CronTrigger适合于复杂的任务，使用cron表达式来定义执行规则。CalendarIntervalTrigger类似于SimpleTrigger，指定从某一个时间开始，以一定的时间间隔执行的任务。 但是CalendarIntervalTrigger执行任务的时间间隔比SimpleTrigger要丰富，它支持的间隔单位有秒，分钟，小时，天，月，年，星期。相较于SimpleTrigger有两个优势：1、更方便，比如每隔1小时执行，你不用自己去计算1小时等于多少毫秒。 2、支持不是固定长度的间隔，比如间隔为月和年。但劣势是精度只能到秒。它的主要两个属性，interval 执行间隔；intervalUnit 执行间隔的单位（秒，分钟，小时，天，月，年，星期）DailyTimeIntervalTrigger指定每天的某个时间段内，以一定的时间间隔执行任务。并且它可以支持指定星期。它适合的任务类似于：指定每天9:00 至 18:00 ，每隔70秒执行一次，并且只要周一至周五执行。它的属性有startTimeOfDay 每天开始时间；endTimeOfDay 每天结束时间；daysOfWeek 需要执行的星期；interval 执行间隔；intervalUnit 执行间隔的单位（秒，分钟，小时，天，月，年，星期）；repeatCount 重复次数所有的trigger都包含了StartTime和endTIme这两个属性，用来指定Trigger被触发的时间区间。所有的trigger都可以设置MisFire策略，该策略是对于由于系统奔溃或者任务时间过长等原因导致trigger在应该触发的时间点没有触发，并且超过了misfireThreshold设置的时间（默认是一分钟，没有超过就立即执行）就算misfire了，这个时候就该设置如何应对这种变化了。激活失败指令（Misfire Instructions）是触发器的一个重要属性，它指定了misfire发生时调度器应当如何处理。所有类型的触发器都有一个默认的指令，叫做Trigger.MISFIRE_INSTRUCTION_SMART_POLICY，但是这个这个“聪明策略”对于不同类型的触发器其具体行为是不同的。对于SimpleTrigger，这个“聪明策略”将根据触发器实例的状态和配置来决定其行 为。具体如下：如果Repeat Count=0：只执行一次instruction selected = MISFIRE_INSTRUCTION_FIRE_NOW;如果Repeat Count=REPEAT_INDEFINITELY：无限次执行instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT;如果Repeat Count>0： 执行多次（有限）instruction selected = MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT;SimpleTrigger常见策略：MISFIRE_INSTRUCTION_FIRE_NOW 立刻执行。对于不会重复执行的任务，这是默认的处理策略。MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT 在下一个激活点执行，且超时期内错过的执行机会作废。MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_COUNT 立即执行，且超时期内错过的执行机会作废。MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT 在下一个激活点执行，并重复到指定的次数。MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_COUNT 立即执行，并重复到指定的次数。MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY 忽略所有的超时状态，按照触发器的策略执行。对于CronTrigger，该“聪明策略”默认选择MISFIRE_INSTRUCTION_FIRE_ONCE_NOW以指导其行为。CronTrigger常见策略：MISFIRE_INSTRUCTION_FIRE_ONCE_NOW 立刻执行一次，然后就按照正常的计划执行。MISFIRE_INSTRUCTION_DO_NOTHING 目前不执行，然后就按照正常的计划执行。这意味着如果下次执行时间超过了end time，实际上就没有执行机会了。三、作业（Job）Job是一个任务接口，开发者定义自己的任务须实现该接口实现void execute(JobExecutionContext context)方法，JobExecutionContext中提供了调度上下文的各种信息。Job中的任务有可能并发执行，例如任务的执行时间过长，而每次触发的时间间隔太短，则会导致任务会被并发执行。如果是并发执行，就需要一个数据库锁去避免一个数据被多次处理。可以在execute()方法上添加注解@DisallowConcurrentExecution解决这个问题。四、作业详情（JobDetail）Quartz在每次执行Job时，都重新创建一个Job实例，所以它不直接接受一个Job的实例，相反它接收一个Job实现类，以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息，如Job名字、描述、关联监听器等信息，JobDetail承担了这一角色。所以说JobDetail是任务的定义，而Job是任务的执行逻辑。五、日历（Calendar）Calendar：org.quartz.Calendar和java.util.Calendar不同，它是一些日历特定时间点的集合（可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点，无特殊说明后面的Calendar即指org.quartz.Calendar）。一个Trigger可以和多个Calendar关联，以便排除或包含某些时间点。主要有以下CalendarHolidayCalendar：指定特定的日期，比如20140613。精度到天。DailyCalendar：指定每天的时间段（rangeStartingTime, rangeEndingTime)，格式是HH:MM[:SS[:mmm]]，也就是最大精度可以到毫秒。WeeklyCalendar：指定每星期的星期几，可选值比如为java.util.Calendar.SUNDAY。精度是天。MonthlyCalendar：指定每月的几号。可选值为1-31。精度是天AnnualCalendar： 指定每年的哪一天。使用方式如上例。精度是天。CronCalendar：指定Cron表达式。精度取决于Cron表达式，也就是最大精度可以到秒。六、JobDataMap用来保存JobDetail运行时的信息，JobDataMap的使用：.usingJobData("name","kyle")或者.getJobDataMap("name","kyle")七、cron表达式Cron表达式对特殊字符的大小写不敏感，对代表星期的缩写英文大小写也不敏感。星号(*)：可用在所有字段中，表示对应时间域的每一个时刻，例如， 在分钟字段时，表示“每分钟”；问号（?）：该字符只在日期和星期字段中使用，它通常指定为“无意义的值”，相当于点位符；减号(-)：表达一个范围，如在小时字段中使用“10-12”，则表示从10到12点，即10,11,12；逗号(,)：表达一个列表值，如在星期字段中使用“MON,WED,FRI”，则表示星期一，星期三和星期五；斜杠(/)：x/y表达一个等步长序列，x为起始值，y为增量步长值。如在分钟字段中使用0/15，则表示为0,15,30和45秒，而5/15在分钟字段中表示5,20,35,50，你也可以使用*/y，它等同于0/y；L：该字符只在日期和星期字段中使用，代表“Last”的意思，但它在两个字段中意思不同。L在日期字段中，表示这个月份的最后一天，如一月的31号，非闰年二月的28号；如果L用在星期中，则表示星期六，等同于7。但是，如果L出现在星期字段里，而且在前面有一个数值X，则表示“这个月的最后X天”，例如，6L表示该月的最后星期五；W：该字符只能出现在日期字段里，是对前导日期的修饰，表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日，如果该月15号是星期六，则匹配14号星期五；如果15日是星期日，则匹配16号星期一；如果15号是星期二，那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月，如你指定1W，如果1号是星期六，结果匹配的是3号星期一，而非上个月最后的那天。W字符串只能指定单一日期，而不能指定日期范围；LW组合：在日期字段可以组合使用LW，它的意思是当月的最后一个工作日；井号(#)：该字符只能在星期字段中使用，表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五，#3表示当前的第三个)，而4#5表示当月的第五个星期三，假设当月没有第五个星期三，忽略不触发；C：该字符只在日期和星期字段中使用，代表“Calendar”的意思。它的意思是计划所关联的日期，如果日期没有被关联，则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。八、quartz.properties文件编写RAMJob的配置####################RAMJob的配置################## #在集群中每个实例都必须有一个唯一的instanceId，但是应该有一个相同的instanceName【默认“QuartzScheduler”】【非必须】 org.quartz.scheduler.instanceName = MyScheduler #Scheduler实例ID，全局唯一，【默认值NON_CLUSTERED】，或者可以使用“SYS_PROP”通过系统属性设置id。【非必须】 org.quartz.scheduler.instanceId=AUTO # 线程池的实现类（定长线程池，几乎可满足所有用户的需求）【默认null】【必须】 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool # 指定线程数，至少为1（无默认值）(一般设置为1-100直接的整数合适)【默认-1】【必须】 org.quartz.threadPool.threadCount = 25 # 设置线程的优先级（最大为java.lang.Thread.MAX_PRIORITY 10，最小为Thread.MIN_PRIORITY 1）【默认Thread.NORM_PRIORITY (5)】【非必须】 org.quartz.threadPool.threadPriority = 5 #misfire设置的时间默认为一分钟 org.quartz.jobStore.misfireThreshold=60000 # 将schedule相关信息保存在RAM中，轻量级，速度快，遗憾的是应用重启时相关信息都将丢失。 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore # 建议设置为“org.terracotta.quartz.skipUpdateCheck=true”不会在程序运行中还去检查quartz是否有版本更新。【默认false】【非必须】 org.quartz.scheduler.skipUpdateCheck = truejdbcJobStore配置###################jdbcJobStore############################ org.quartz.scheduler.instanceName=MyScheduler org.quartz.scheduler.instanceId=AUTO org.quartz.threadPool.threadCount=3 # 所有的quartz数据例如job和Trigger的细节信息被保存在内存或数据库中,有两种实现：JobStoreTX(自己管理事务) #和JobStoreCMT（application server管理事务，即全局事务JTA） org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX # 类似于Hibernate的dialect，用于处理DB之间的差异，StdJDBCDelegate能满足大部分的DB org.quartz.jobStore.driverDelegateClass =org.quartz.impl.jdbcjobstore.StdJDBCDelegate #数据库表的前缀 org.quartz.jobStore.tablePrefix=QRTZ_ #配置数据源的名称 org.quartz.jobStore.dataSource=myDS #为了指示JDBCJobStore所有的JobDataMaps中的值都是字符串，并且能以“名字-值”对的方式存储而不是以复杂对象的序列化形式存储在BLOB字段中，应该设置为true(缺省方式) org.quartz.jobStore.useProperties = true # 检入到数据库中的频率(毫秒)。检查是否其他的实例到了应当检入的时候未检入这能指出一个失败的实例， #且当前Scheduler会以此来接管执行失败并可恢复的Job通过检入操作，Scheduler也会更新自身的状态记录 org.quartz.jobStore.clusterCheckinInterval=20000 # 是否集群、负载均衡、容错，如果应用在集群中设置为false会出错 org.quartz.jobStore.isClustered=false #misfire时间设置 org.quartz.jobStore.misfireThreshold=60000 # 连接超时重试连接的间隔。使用 RamJobStore时，该参数并没什么用【默认15000】【非必须】 #org.quartz.scheduler.dbFailureRetryInterval = 15000 #下面是数据库链接相关的配置 org.quartz.dataSource.myDS.driver=com.mysql.jdbc.Driver org.quartz.dataSource.myDS.URL=jdbc:mysql://localhost:3306/zproject?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC org.quartz.dataSource.myDS.user=root org.quartz.dataSource.myDS.password=root org.quartz.dataSource.myDS.maxConnections=5参考资料quartz基本介绍和使用