quartz-project: quartz
2. 环境信息springboot 2.5.4
3. 搭建流程 3.1 创建一个springboot项目 (略) 3.2 pom.xmlapplication.ymlorg.springframework.boot spring-boot-starterorg.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-quartzorg.projectlombok lomboktrue mysql mysql-connector-javacom.alibaba druid-spring-boot-starter1.1.20 com.baomidou mybatis-plus-boot-starter3.4.2 com.baomidou mybatis-plus-generator3.4.1 cn.hutool hutool-all5.3.4 com.vdurmont emoji-java4.0.0
server:
port: 9999
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
password: 123456
url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowMutiQueries=true
username: root
# 配置数据库连接池
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 1
min-idle: 1
max-active: 20
max-wait: 60000
test-while-idle: true
time-between-connect-error-millis: 60000
min-evictable-idle-time-millis: 30000
validation-query: select 'x'
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
use-global-data-source-stat: false
filters: stat,wall,slf4j
connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
time-between-log-stats-millis: 300000
username: ${spring.datasource.username}
password: ${spring.datasource.password}
url : ${spring.datasource.url}
driver-class-name: ${spring.datasource.driver-class-name}
quartz.properties
#主要分为scheduler、threadPool、jobStore、dataSource等部分 org.quartz.scheduler.instanceId=AUTO #如果您希望Quartz Scheduler通过RMI作为服务器导出本身,则将“rmi.export”标志设置为true #在同一个配置文件中为'org.quartz.scheduler.rmi.export'和'org.quartz.scheduler.rmi.proxy'指定一个'true'值是没有意义的,如果你这样做'export'选项将被忽略 org.quartz.scheduler.rmi.export=false #如果要连接(使用)远程服务的调度程序,则将“org.quartz.scheduler.rmi.proxy”标志设置为true。您还必须指定RMI注册表进程的主机和端口 - 通常是“localhost”端口1099 org.quartz.scheduler.rmi.proxy=false org.quartz.scheduler.wrapJobExecutionInUserTransaction=false #实例化ThreadPool时,使用的线程类为SimpleThreadPool org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool #threadCount和threadPriority将以setter的形式注入ThreadPool实例 #并发个数 如果你只有几个工作每天触发几次 那么1个线程就可以,如果你有成千上万的工作,每分钟都有很多工作 那么久需要50-100之间. #只有1到100之间的数字是非常实用的 org.quartz.threadPool.threadCount=5 #优先级 默认值为5 org.quartz.threadPool.threadPriority=5 #可以是“true”或“false”,默认为false org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true #在被认为“misfired”(失火)之前,调度程序将“tolerate(容忍)”一个Triggers(触发器)将其下一个启动时间通过的毫秒数。默认值(如果您在配置中未输入此属性)为60000(60秒) org.quartz.jobStore.misfireThreshold=5000 # 默认存储在内存中,RAMJobStore快速轻便,但是当进程终止时,所有调度信息都会丢失 #org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore #持久化方式,默认存储在内存中,此处使用数据库方式 org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX #您需要为JobStore选择一个DriverDelegate才能使用。DriverDelegate负责执行特定数据库可能需要的任何JDBC工作 # StdJDBCDelegate是一个使用“vanilla”JDBC代码(和SQL语句)来执行其工作的委托,用于完全符合JDBC的驱动程序 org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate #可以将“org.quartz.jobStore.useProperties”配置参数设置为“true”(默认为false),以指示JDBCJobStore将JobDataMaps中的所有值都作为字符串, #因此可以作为名称 - 值对存储而不是在BLOB列中以其序列化形式存储更多复杂的对象。从长远来看,这是更安全的,因为您避免了将非String类序列化为BLOB的类版本问题 org.quartz.jobStore.useProperties=true #表前缀 org.quartz.jobStore.tablePrefix=QRTZ_ #数据源别名,自定义 org.quartz.jobStore.dataSource=qzDS #使用阿里的druid作为数据库连接池 org.quartz.dataSource.qzDS.connectionProvider.class=com.hctrl.quartz.config.DruidConnectionProvider org.quartz.dataSource.qzDS.URL=jdbc:mysql://127.0.0.1:3306/quartz?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTC org.quartz.dataSource.qzDS.user=root org.quartz.dataSource.qzDS.password=123456 org.quartz.dataSource.qzDS.driver=com.mysql.cj.jdbc.Driver org.quartz.dataSource.qzDS.maxConnection=10 #设置为“true”以打开群集功能。如果您有多个Quartz实例使用同一组数据库表,则此属性必须设置为“true”,否则您将遇到破坏 #org.quartz.jobStore.isClustered=falsequartz.sql (项目启动不会自动创建表, 需要在数据库中手动创建表)
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for qrtz_blob_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_blob_triggers`; CREATE TABLE `qrtz_blob_triggers` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名', `trigger_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器名称', `trigger_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器组', `blob_data` blob, PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, INDEX `sched_name`(`sched_name`) USING BTREE, CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '以blob 类型存储的触发器' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_calendars -- ---------------------------- DROP TABLE IF EXISTS `qrtz_calendars`; CREATE TABLE `qrtz_calendars` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `calendar_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `calendar` blob NOT NULL, PRIMARY KEY (`sched_name`, `calendar_name`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '日历信息表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_cron_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_cron_triggers`; CREATE TABLE `qrtz_cron_triggers` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `trigger_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器名称', `trigger_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器组', `cron_expression` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '时间表达式', `time_zone_id` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '时区id', PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '定时触发器表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_fired_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_fired_triggers`; CREATE TABLE `qrtz_fired_triggers` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `entry_id` varchar(95) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '组标识', `trigger_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器名称', `trigger_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器组', `instance_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '当前实例的名称', `fired_time` bigint(0) NOT NULL COMMENT '当前执行时间', `sched_time` bigint(0) NOT NULL COMMENT '计划时间', `priority` int(0) NOT NULL COMMENT '权重', `state` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '状态', `job_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '作业名称', `job_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '作业组', `is_nonconcurrent` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '是否并行', `requests_recovery` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '是否要求唤醒', PRIMARY KEY (`sched_name`, `entry_id`) USING BTREE, INDEX `idx_qrtz_ft_trig_inst_name`(`sched_name`, `instance_name`) USING BTREE, INDEX `idx_qrtz_ft_inst_job_req_rcvry`(`sched_name`, `instance_name`, `requests_recovery`) USING BTREE, INDEX `idx_qrtz_ft_j_g`(`sched_name`, `job_name`, `job_group`) USING BTREE, INDEX `idx_qrtz_ft_jg`(`sched_name`, `job_group`) USING BTREE, INDEX `idx_qrtz_ft_t_g`(`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, INDEX `idx_qrtz_ft_tg`(`sched_name`, `trigger_group`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '保存已经触发的触发器状态信息' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_job_details -- ---------------------------- DROP TABLE IF EXISTS `qrtz_job_details`; CREATE TABLE `qrtz_job_details` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `job_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '作业名称', `job_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '作业组', `description` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述', `job_class_name` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '作业程序类名', `is_durable` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '是否持久', `is_nonconcurrent` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '是否并行', `is_update_data` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '是否更新', `requests_recovery` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '是否要求唤醒', `job_data` blob COMMENT '作业名称', PRIMARY KEY (`sched_name`, `job_name`, `job_group`) USING BTREE, INDEX `idx_qrtz_j_req_recovery`(`sched_name`, `requests_recovery`) USING BTREE, INDEX `idx_qrtz_j_grp`(`sched_name`, `job_group`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'job 详细信息表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_locks -- ---------------------------- DROP TABLE IF EXISTS `qrtz_locks`; CREATE TABLE `qrtz_locks` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `lock_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '锁名称', PRIMARY KEY (`sched_name`, `lock_name`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '存储程序的悲观锁的信息(假如使用了悲观锁) ' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_paused_trigger_grps -- ---------------------------- DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`; CREATE TABLE `qrtz_paused_trigger_grps` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `trigger_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器组', PRIMARY KEY (`sched_name`, `trigger_group`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '存放暂停掉的触发器表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_scheduler_state -- ---------------------------- DROP TABLE IF EXISTS `qrtz_scheduler_state`; CREATE TABLE `qrtz_scheduler_state` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `instance_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '实例名称', `last_checkin_time` bigint(0) NOT NULL COMMENT '最后的检查时间', `checkin_interval` bigint(0) NOT NULL COMMENT '检查间隔', PRIMARY KEY (`sched_name`, `instance_name`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '调度器状态表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_simple_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_simple_triggers`; CREATE TABLE `qrtz_simple_triggers` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `trigger_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器名称', `trigger_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器组', `repeat_count` bigint(0) NOT NULL COMMENT '重复次数', `repeat_interval` bigint(0) NOT NULL COMMENT '重复间隔', `times_triggered` bigint(0) NOT NULL COMMENT '触发次数', PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '简单的触发器表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_simprop_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_simprop_triggers`; CREATE TABLE `qrtz_simprop_triggers` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `trigger_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器名称', `trigger_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器组', `str_prop_1` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '计划名称', `str_prop_2` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '计划名称', `str_prop_3` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '计划名称', `int_prop_1` int(0) DEFAULT NULL, `int_prop_2` int(0) DEFAULT NULL, `long_prop_1` bigint(0) DEFAULT NULL, `long_prop_2` bigint(0) DEFAULT NULL, `dec_prop_1` decimal(13, 4) DEFAULT NULL, `dec_prop_2` decimal(13, 4) DEFAULT NULL, `bool_prop_1` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, `bool_prop_2` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '存储两种类型的触发器表' ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for qrtz_triggers -- ---------------------------- DROP TABLE IF EXISTS `qrtz_triggers`; CREATE TABLE `qrtz_triggers` ( `sched_name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '计划名称', `trigger_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器名称', `trigger_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器组', `job_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '作业名称', `job_group` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '作业组', `description` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '描述', `next_fire_time` bigint(0) DEFAULT NULL COMMENT '下次执行时间', `prev_fire_time` bigint(0) DEFAULT NULL COMMENT '前一次', `priority` int(0) DEFAULT NULL COMMENT '优先权', `trigger_state` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器状态', `trigger_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '触发器类型', `start_time` bigint(0) NOT NULL COMMENT '开始时间', `end_time` bigint(0) DEFAULT NULL COMMENT '结束时间', `calendar_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '日历名称', `misfire_instr` smallint(0) DEFAULT NULL COMMENT '失败次数', `job_data` blob COMMENT '作业数据', PRIMARY KEY (`sched_name`, `trigger_name`, `trigger_group`) USING BTREE, INDEX `idx_qrtz_t_j`(`sched_name`, `job_name`, `job_group`) USING BTREE, INDEX `idx_qrtz_t_jg`(`sched_name`, `job_group`) USING BTREE, INDEX `idx_qrtz_t_c`(`sched_name`, `calendar_name`) USING BTREE, INDEX `idx_qrtz_t_g`(`sched_name`, `trigger_group`) USING BTREE, INDEX `idx_qrtz_t_state`(`sched_name`, `trigger_state`) USING BTREE, INDEX `idx_qrtz_t_n_state`(`sched_name`, `trigger_name`, `trigger_group`, `trigger_state`) USING BTREE, INDEX `idx_qrtz_t_n_g_state`(`sched_name`, `trigger_group`, `trigger_state`) USING BTREE, INDEX `idx_qrtz_t_next_fire_time`(`sched_name`, `next_fire_time`) USING BTREE, INDEX `idx_qrtz_t_nft_st`(`sched_name`, `trigger_state`, `next_fire_time`) USING BTREE, INDEX `idx_qrtz_t_nft_misfire`(`sched_name`, `misfire_instr`, `next_fire_time`) USING BTREE, INDEX `idx_qrtz_t_nft_st_misfire`(`sched_name`, `misfire_instr`, `next_fire_time`, `trigger_state`) USING BTREE, INDEX `idx_qrtz_t_nft_st_misfire_grp`(`sched_name`, `misfire_instr`, `next_fire_time`, `trigger_group`, `trigger_state`) USING BTREE, CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `qrtz_job_details` (`sched_name`, `job_name`, `job_group`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '触发器表' ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;3.3 代码
DruidConfig : druid数据源配置
package com.hctrl.quartz.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.hctrl.quartz.properties.DruidDataSourceProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
@Configuration
@EnableConfigurationProperties({ DruidDataSourceProperties.class })
public class DruidConfig {
@Bean
@ConditionalOnMissingBean
public DataSource druidDataSource1(DruidDataSourceProperties properties) {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(properties.getDriverClassName());
druidDataSource.setUrl(properties.getUrl());
druidDataSource.setUsername(properties.getUsername());
druidDataSource.setPassword(properties.getPassword());
druidDataSource.setInitialSize(properties.getInitialSize());
druidDataSource.setMinIdle(properties.getMinIdle());
druidDataSource.setMaxActive(properties.getMaxActive());
druidDataSource.setMaxWait(properties.getMaxWait());
druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
druidDataSource.setValidationQuery(properties.getValidationQuery());
druidDataSource.setTestWhileIdle(properties.isTestWhileIdle());
druidDataSource.setTestOnBorrow(properties.isTestOnBorrow());
druidDataSource.setTestOnReturn(properties.isTestOnReturn());
druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements());
druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(
properties.getMaxPoolPreparedStatementPerConnectionSize());
try {
druidDataSource.init();
} catch (SQLException e) {
e.printStackTrace();
}
return druidDataSource;
}
}
DruidConnectionProvider : 将quartz数据源修改为druid, 类中的属性会自动读取配置文件, 写好get, set方法即可
package com.hctrl.quartz.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.quartz.SchedulerException;
import org.quartz.utils.ConnectionProvider;
import java.sql.Connection;
import java.sql.SQLException;
public class DruidConnectionProvider implements ConnectionProvider {
//JDBC驱动
public String driver;
//JDBC连接串
public String URL;
//数据库用户名
public String user;
//数据库用户密码
public String password;
//数据库最大连接数
public int maxConnection;
//数据库SQL查询每次连接返回执行到连接池,以确保它仍然是有效的。
public String validationQuery;
private boolean validateOnCheckout;
private int idleConnectionValidationSeconds;
public String maxCachedStatementsPerConnection;
private String discardIdleConnectionsSeconds;
public static final int DEFAULT_DB_MAX_CONNECTIONS = 10;
public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120;
private DruidDataSource datasource;
public Connection getConnection() throws SQLException {
return datasource.getConnection();
}
public void shutdown() throws SQLException {
datasource.close();
}
public void initialize() throws SQLException{
if (this.URL == null) {
throw new SQLException("DBPool could not be created: DB URL cannot be null");
}
if (this.driver == null) {
throw new SQLException("DBPool driver could not be created: DB driver class name cannot be null!");
}
if (this.maxConnection < 0) {
throw new SQLException("DBPool maxConnectins could not be created: Max connections must be greater than zero!");
}
datasource = new DruidDataSource();
try{
datasource.setDriverClassName(this.driver);
} catch (Exception e) {
try {
throw new SchedulerException("Problem setting driver class name on datasource: " + e.getMessage(), e);
} catch (SchedulerException e1) {
}
}
datasource.setUrl(this.URL);
datasource.setUsername(this.user);
datasource.setPassword(this.password);
datasource.setMaxActive(this.maxConnection);
datasource.setMinIdle(1);
datasource.setMaxWait(0);
datasource.setMaxPoolPreparedStatementPerConnectionSize(this.DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION);
if (this.validationQuery != null) {
datasource.setValidationQuery(this.validationQuery);
if(!this.validateOnCheckout)
datasource.setTestOnReturn(true);
else
datasource.setTestOnBorrow(true);
datasource.setValidationQueryTimeout(this.idleConnectionValidationSeconds);
}
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getURL() {
return URL;
}
public void setURL(String URL) {
this.URL = URL;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getMaxConnection() {
return maxConnection;
}
public void setMaxConnection(int maxConnection) {
this.maxConnection = maxConnection;
}
public String getValidationQuery() {
return validationQuery;
}
public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
}
public boolean isValidateOnCheckout() {
return validateOnCheckout;
}
public void setValidateOnCheckout(boolean validateOnCheckout) {
this.validateOnCheckout = validateOnCheckout;
}
public int getIdleConnectionValidationSeconds() {
return idleConnectionValidationSeconds;
}
public void setIdleConnectionValidationSeconds(int idleConnectionValidationSeconds) {
this.idleConnectionValidationSeconds = idleConnectionValidationSeconds;
}
public DruidDataSource getDatasource() {
return datasource;
}
public void setDatasource(DruidDataSource datasource) {
this.datasource = datasource;
}
}
QuartzConfig : quartz配置类
package com.hctrl.quartz.config;
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;
@Configuration
public class QuartzConfig implements SchedulerFactoryBeanCustomizer {
@Resource
private DataSource druidDataSource1;
@Bean
public Properties properties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
// 对quartz.properties文件进行读取
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
// 在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
// schedulerFactoryBean.setQuartzProperties(properties());
//此处一定要配置数据源, 否则创建的任务和触发器不用存入到数据库中
schedulerFactoryBean.setDataSource(druidDataSource1);
return schedulerFactoryBean;
}
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
@Bean
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
@Override
public void customize(SchedulerFactoryBean schedulerFactoryBean) {
schedulerFactoryBean.setStartupDelay(2);
schedulerFactoryBean.setAutoStartup(true);
schedulerFactoryBean.setOverwriteExistingJobs(true);
}
}
DruidDataSourceProperties : 读取配置文件的配置信息, 创建druid数据源使用
package com.hctrl.quartz.properties;
import lombok.Data;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix="spring.datasource.druid")
@Data
public class DruidDataSourceProperties {
private String driverClassName;
private String url;
private String username;
private String password;
// jdbc connection pool
private int initialSize;
private int minIdle;
private int maxActive = 100;
private long maxWait;
private long timeBetweenEvictionRunsMillis;
private long minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxPoolPreparedStatementPerConnectionSize;
// filter
private String filters;
}
controller :
package com.hctrl.quartz.controller;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.pattern.CronPattern;
import cn.hutool.cron.pattern.CronPatternUtil;
import com.hctrl.quartz.service.QuartzService;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import result.BaseResult;
import result.CommonResult;
@RestController
@RequestMapping("/v1/quartz")
public class QuartzController {
@Autowired
private QuartzService quartzService;
@PostMapping(path = "/addJob")
public BaseResult addJob(String jName, String jGroup, String tName, String tGroup, String cron) {
try {
if (cron == null){
cron = "*/5 * * * * ?";
}
quartzService.addJob(jName, jGroup, tName, tGroup, cron);
return CommonResult.buildSuccess("添加任务成功");
} catch (Exception e) {
e.printStackTrace();
return CommonResult.buildFailure(500,"添加任务失败");
}
}
@PostMapping(path = "/pauseJob")
public BaseResult pauseJob(String jName, String jGroup) {
try {
quartzService.pauseJob(jName, jGroup);
return CommonResult.buildSuccess("暂停任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
return CommonResult.buildFailure(500,"暂停任务失败");
}
}
@PostMapping(path = "/resumeJob")
public BaseResult resumeJob(String jName, String jGroup) {
try {
quartzService.resumeJob(jName, jGroup);
return CommonResult.buildSuccess("恢复任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
return CommonResult.buildFailure(500,"恢复任务失败");
}
}
@PostMapping(path = "/reScheduleJob")
public BaseResult rescheduleJob(String jName, String jGroup, String cron) {
try {
quartzService.reScheduleJob(jName, jGroup, cron);
return CommonResult.buildSuccess("重启任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
return CommonResult.buildFailure(500,"重启任务失败");
}
}
@PostMapping(path = "/deleteJob")
public BaseResult deleteJob(String jName, String jGroup) {
try {
quartzService.deleteJob(jName, jGroup);
return CommonResult.buildSuccess("删除任务成功");
} catch (SchedulerException e) {
e.printStackTrace();
return CommonResult.buildFailure(500,"删除任务失败");
}
}
}
service :
package com.hctrl.quartz.service;
import com.hctrl.quartz.Job.HelloJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class QuartzService {
@Autowired
private Scheduler scheduler;
public void addJob(String jName, String jGroup, String tName, String tGroup, String cron) {
try {
// 构建JobDetail, 可以设置dataMap, 用于传递参数
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity(jName, jGroup)
.build();
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(tName, tGroup)
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
// 启动调度器
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
log.info("创建定时任务失败" + e);
}
}
public void pauseJob(String jName, String jGroup) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(jName, jGroup));
}
public void resumeJob(String jName, String jGroup) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(jName, jGroup));
}
public void reScheduleJob(String jName, String jGroup, String cron) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(jName, jGroup);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行,重启触发器
scheduler.rescheduleJob(triggerKey, trigger);
}
public void deleteJob(String jName, String jGroup) throws SchedulerException {
scheduler.pauseTrigger(TriggerKey.triggerKey(jName, jGroup));
scheduler.unscheduleJob(TriggerKey.triggerKey(jName, jGroup));
scheduler.deleteJob(JobKey.jobKey(jName, jGroup));
}
}
HelloJob : 执行任务类, 主要逻辑
package com.hctrl.quartz.Job;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.PersistJobDataAfterExecution;
import java.time.LocalDateTime;
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) {
String name = context.getJobDetail().getKey().getName();
String format = DateUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN);
System.out.println(name + " Hello Job执行时间: " + format);
}
}
结果图 :



