Springboot2.x+Quartz分布式集群的实现

时间:2022-04-20 05:42:51

生产环境一般都是多节点高可用,Springboot本身自带有定时任务功能,但我们项目需求要求能对定时任务进行增,删,改,查。所以考虑引进Quartz,引入Quartz就需要考虑分布式集群,所以就有了这篇文章。

数据库脚本

Quartz数据库有11张表,既支持Mysql,也支持Oracle

Mysql

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
/*
Navicat MySQL Data Transfer
 
Source Server     : 10.19.34.3_ehr_admin
Source Server Version : 50639
Source Host      : 10.19.34.3:3306
Source Database    : attend_base_dev
 
Target Server Type  : MYSQL
Target Server Version : 50639
File Encoding     : 65001
 
Date: 2020-08-28 16:29:36
*/
 
-- SET FOREIGN_KEY_CHECKS=0;
 
-- ----------------------------
-- Table structure for `qrtz_CALENDARS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_CALENDARS`;
CREATE TABLE `qrtz_CALENDARS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `CALENDAR_NAME` varchar(200) NOT NULL,
 `CALENDAR` blob NOT NULL,
 PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='日历信息';
 
-- ----------------------------
-- Records of qrtz_CALENDARS
-- ----------------------------
 
-- ----------------------------
-- Table structure for `qrtz_FIRED_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_FIRED_TRIGGERS`;
CREATE TABLE `qrtz_FIRED_TRIGGERS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `ENTRY_ID` varchar(95) NOT NULL COMMENT '组标识',
 `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
 `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
 `INSTANCE_NAME` varchar(200) NOT NULL COMMENT '当前实例的名称',
 `FIRED_TIME` bigint(13) NOT NULL COMMENT '当前执行时间',
 `SCHED_TIME` bigint(13) NOT NULL COMMENT '计划时间',
 `PRIORITY` int(11) NOT NULL COMMENT '权重',
 `STATE` varchar(16) NOT NULL COMMENT '状态:WAITING:等待 \r\nPAUSED:暂停 \r\nACQUIRED:正常执行 \r\nBLOCKED:阻塞 \r\nERROR:错误',
 `JOB_NAME` varchar(200) DEFAULT NULL COMMENT '作业名称',
 `JOB_GROUP` varchar(200) DEFAULT NULL COMMENT '作业组',
 `IS_NONCONCURRENT` varchar(1) DEFAULT NULL COMMENT '是否并行',
 `REQUESTS_RECOVERY` varchar(1) DEFAULT NULL COMMENT '是否要求唤醒',
 PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
 KEY `IDX_qrtz_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
 KEY `IDX_qrtz_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
 KEY `IDX_qrtz_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
 KEY `IDX_qrtz_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
 KEY `IDX_qrtz_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
 KEY `IDX_qrtz_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='保存已经触发的触发器状态信息';
 
-- ----------------------------
-- Records of qrtz_FIRED_TRIGGERS
-- ----------------------------
 
-- ----------------------------
-- Table structure for `qrtz_JOB_DETAILS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_JOB_DETAILS`;
CREATE TABLE `qrtz_JOB_DETAILS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `JOB_NAME` varchar(200) NOT NULL COMMENT '集群中job的名字',
 `JOB_GROUP` varchar(200) NOT NULL COMMENT '集群中job的所属组的名字',
 `DESCRIPTION` varchar(250) DEFAULT NULL COMMENT '描述',
 `JOB_CLASS_NAME` varchar(250) NOT NULL COMMENT '作业程序类名',
 `IS_DURABLE` varchar(1) NOT NULL COMMENT '是否持久',
 `IS_NONCONCURRENT` varchar(1) NOT NULL COMMENT '是否并行',
 `IS_UPDATE_DATA` varchar(1) NOT NULL COMMENT '是否更新',
 `REQUESTS_RECOVERY` varchar(1) NOT NULL COMMENT '是否要求唤醒',
 `JOB_DATA` blob,
 PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
 KEY `IDX_qrtz_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
 KEY `IDX_qrtz_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job 详细信息';
 
-- ----------------------------
-- Records of qrtz_JOB_DETAILS
-- ----------------------------
-- ----------------------------
-- Table structure for `qrtz_LOCKS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_LOCKS`;
CREATE TABLE `qrtz_LOCKS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `LOCK_NAME` varchar(40) NOT NULL COMMENT '锁名称',
 PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存储程序的悲观锁的信息(假如使用了悲观锁) ';
 
-- ----------------------------
-- Records of qrtz_LOCKS
 
-- ----------------------------
-- 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) NOT NULL COMMENT '计划名称',
 `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
 PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存放暂停掉的触发器';
 
-- ----------------------------
-- Records of qrtz_PAUSED_TRIGGER_GRPS
-- ----------------------------
 
-- ----------------------------
-- Table structure for `qrtz_SCHEDULER_STATE`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SCHEDULER_STATE`;
CREATE TABLE `qrtz_SCHEDULER_STATE` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `INSTANCE_NAME` varchar(200) NOT NULL COMMENT '实例名称',
 `LAST_CHECKIN_TIME` bigint(13) NOT NULL COMMENT '最后的检查时间',
 `CHECKIN_INTERVAL` bigint(13) NOT NULL COMMENT '检查间隔',
 PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='调度器状态';
 
-- ----------------------------
-- Records of qrtz_SCHEDULER_STATE
 
-- ----------------------------
-- Table structure for `qrtz_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_TRIGGERS`;
CREATE TABLE `qrtz_TRIGGERS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
 `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
 `JOB_NAME` varchar(200) NOT NULL COMMENT '作业名称',
 `JOB_GROUP` varchar(200) NOT NULL COMMENT '作业组',
 `DESCRIPTION` varchar(250) DEFAULT NULL COMMENT '描述',
 `NEXT_FIRE_TIME` bigint(13) DEFAULT NULL COMMENT '下次执行时间',
 `PREV_FIRE_TIME` bigint(13) DEFAULT NULL COMMENT '前一次',
 `PRIORITY` int(11) DEFAULT NULL COMMENT '优先权',
 `TRIGGER_STATE` varchar(16) NOT NULL COMMENT '触发器状态',
 `TRIGGER_TYPE` varchar(8) NOT NULL COMMENT '触发器类型',
 `START_TIME` bigint(13) NOT NULL COMMENT '开始时间',
 `END_TIME` bigint(13) DEFAULT NULL COMMENT '结束时间',
 `CALENDAR_NAME` varchar(200) DEFAULT NULL COMMENT '日历名称',
 `MISFIRE_INSTR` smallint(2) DEFAULT NULL COMMENT '失败次数',
 `JOB_DATA` blob,
 PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
 KEY `IDX_qrtz_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
 KEY `IDX_qrtz_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
 KEY `IDX_qrtz_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
 KEY `IDX_qrtz_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
 KEY `IDX_qrtz_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
 KEY `IDX_qrtz_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
 KEY `IDX_qrtz_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
 KEY `IDX_qrtz_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
 KEY `IDX_qrtz_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
 KEY `IDX_qrtz_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
 KEY `IDX_qrtz_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
 KEY `IDX_qrtz_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='触发器';
 
-- ----------------------------
-- Records of qrtz_TRIGGERS
 
-- ----------------------------
-- Table structure for `qrtz_SIMPLE_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SIMPLE_TRIGGERS`;
CREATE TABLE `qrtz_SIMPLE_TRIGGERS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
 `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
 `REPEAT_COUNT` bigint(7) NOT NULL COMMENT '重复次数',
 `REPEAT_INTERVAL` bigint(12) NOT NULL COMMENT '重复间隔',
 `TIMES_TRIGGERED` bigint(10) NOT NULL COMMENT '触发次数',
 PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='简单的触发器';
 
-- ----------------------------
-- Records of qrtz_SIMPLE_TRIGGERS
-- ----------------------------
 
-- ----------------------------
-- Table structure for `qrtz_SIMPROP_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_SIMPROP_TRIGGERS`;
CREATE TABLE `qrtz_SIMPROP_TRIGGERS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
 `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
 `STR_PROP_1` varchar(512) DEFAULT NULL,
 `STR_PROP_2` varchar(512) DEFAULT NULL,
 `STR_PROP_3` varchar(512) DEFAULT NULL,
 `INT_PROP_1` int(11) DEFAULT NULL,
 `INT_PROP_2` int(11) DEFAULT NULL,
 `LONG_PROP_1` bigint(20) DEFAULT NULL,
 `LONG_PROP_2` bigint(20) DEFAULT NULL,
 `DEC_PROP_1` decimal(13,4) DEFAULT NULL,
 `DEC_PROP_2` decimal(13,4) DEFAULT NULL,
 `BOOL_PROP_1` varchar(1) DEFAULT NULL,
 `BOOL_PROP_2` varchar(1) DEFAULT NULL,
 PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='存储CalendarIntervalTrigger和DailyTimeIntervalTrigger两种类型的触发器';
 
-- ----------------------------
-- Records of qrtz_SIMPROP_TRIGGERS
-- ----------------------------
 
-- ----------------------------
-- Table structure for `qrtz_BLOB_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_BLOB_TRIGGERS`;
CREATE TABLE `qrtz_BLOB_TRIGGERS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名',
 `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
 `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
 `BLOB_DATA` blob,
 PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
 KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='以Blob 类型存储的触发器';
 
-- ----------------------------
-- Records of qrtz_BLOB_TRIGGERS
-- ----------------------------
 
-- ----------------------------
-- Table structure for `qrtz_CRON_TRIGGERS`
-- ----------------------------
-- DROP TABLE IF EXISTS `qrtz_CRON_TRIGGERS`;
CREATE TABLE `qrtz_CRON_TRIGGERS` (
 `SCHED_NAME` varchar(120) NOT NULL COMMENT '计划名称',
 `TRIGGER_NAME` varchar(200) NOT NULL COMMENT '触发器名称',
 `TRIGGER_GROUP` varchar(200) NOT NULL COMMENT '触发器组',
 `CRON_EXPRESSION` varchar(120) NOT NULL COMMENT '时间表达式',
 `TIME_ZONE_ID` varchar(80) DEFAULT NULL COMMENT '时区ID   nvarchar   80',
 PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='定时触发器';
 
-- ----------------------------
-- Records of qrtz_CRON_TRIGGERS
-- ----------------------------
Oracle
create table QRTZ_CALENDARS
(
 sched_name  VARCHAR2(120) not null,
 calendar_name VARCHAR2(200) not null,
 calendar   BLOB not null
);
alter table QRTZ_CALENDARS
 add constraint PK_QRTZ_CALENDARS primary key (SCHED_NAME, CALENDAR_NAME);
 
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     INTEGER not null,
 state       VARCHAR2(16) not null,
 job_name     VARCHAR2(200),
 job_group     VARCHAR2(200),
 is_nonconcurrent VARCHAR2(1),
 requests_recovery VARCHAR2(1)
);
alter table QRTZ_FIRED_TRIGGERS
 add constraint PK_QRTZ_FIRED_TRIGGERS primary key (SCHED_NAME, ENTRY_ID);
 
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),
 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
);
alter table QRTZ_JOB_DETAILS
 add constraint PK_QRTZ_JOB_DETAILS primary key (SCHED_NAME, JOB_NAME, JOB_GROUP);
 
create table QRTZ_LOCKS
(
 sched_name VARCHAR2(120) not null,
 lock_name VARCHAR2(40) not null
);
alter table QRTZ_LOCKS
 add constraint PK_QRTZ_LOCKS primary key (SCHED_NAME, LOCK_NAME);
 
create table QRTZ_PAUSED_TRIGGER_GRPS
(
 sched_name  VARCHAR2(120) not null,
 trigger_group VARCHAR2(200) not null
);
alter table QRTZ_PAUSED_TRIGGER_GRPS
 add constraint PK__TRIGGER_GRPS primary key (SCHED_NAME, TRIGGER_GROUP);
 
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
);
alter table QRTZ_SCHEDULER_STATE
 add constraint PK_QRTZ_SCHEDULER_STATE primary key (SCHED_NAME, INSTANCE_NAME);
 
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),
 next_fire_time NUMBER(13),
 prev_fire_time NUMBER(13),
 priority    INTEGER,
 trigger_state VARCHAR2(16) not null,
 trigger_type  VARCHAR2(8) not null,
 start_time   NUMBER(13) not null,
 end_time    NUMBER(13),
 calendar_name VARCHAR2(200),
 misfire_instr NUMBER(2),
 job_data    BLOB
);
 
alter table QRTZ_TRIGGERS
 add constraint PK_QRTZ_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_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
);
alter table QRTZ_SIMPLE_TRIGGERS
 add constraint PK_QRTZ_SIMPLE_TRIGGERS primary key (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),
 str_prop_2  VARCHAR2(512),
 str_prop_3  VARCHAR2(512),
 int_prop_1  INTEGER,
 int_prop_2  INTEGER,
 long_prop_1  NUMBER,
 long_prop_2  NUMBER,
 dec_prop_1  NUMBER(13,4),
 dec_prop_2  NUMBER(13,4),
 bool_prop_1  VARCHAR2(1),
 bool_prop_2  VARCHAR2(1)
);
alter table QRTZ_SIMPROP_TRIGGERS
 add constraint PK_QRTZ_SIMPROP_TRIGGERS primary key (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
);
alter table QRTZ_BLOB_TRIGGERS
 add constraint PK_QRTZ_BLOB_TRIGGERS primary key (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(200) not null,
 time_zone_id  VARCHAR2(80)
);
alter table QRTZ_CRON_TRIGGERS
 add constraint PK_QRTZ_CRON_TRIGGERS primary key (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
 
delete from QRTZ_JOB_DETAILS;
delete from QRTZ_CRON_TRIGGERS;
delete from QRTZ_BLOB_TRIGGERS;
delete from QRTZ_CALENDARS;
delete from QRTZ_FIRED_TRIGGERS;
delete from QRTZ_LOCKS;
delete from QRTZ_PAUSED_TRIGGER_GRPS;
delete from QRTZ_SCHEDULER_STATE;
delete from QRTZ_SIMPLE_TRIGGERS;
delete from QRTZ_SIMPROP_TRIGGERS;
delete from QRTZ_TRIGGERS;

Maven

我这里后台使用的是Springboot2.1

?
1
2
3
4
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

application.yml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
quartz:
  #quartz相关属性配置
  properties:
   org:
    quartz:
     scheduler:
      instanceName: clusteredScheduler #调度器的实例名
      instanceId: AUTO #调度器编号自动生成
     jobStore:
      class: org.quartz.impl.jdbcjobstore.JobStoreTX
      driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
      tablePrefix: qrtz_ #数据库表名前缀
      isClustered: true #开启分布式部署
      clusterCheckinInterval: 10000 #分布式节点有效性检查时间间隔,单位:秒
      useProperties: false
     threadPool:
      class: org.quartz.simpl.SimpleThreadPool #自带的线程池实现类
      threadCount: 10 #开启10个线程
      threadPriority: 5 #工作者线程的优先级
      threadsInheritContextClassLoaderOfInitializingThread: true
  #数据库方式
  job-store-type: jdbc

Bean

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import org.quartz.JobDataMap;
import java.util.Date;
 
/**
 * @program: QuartzBean
 * @description:
 * @author: Yuwl
 * @create: 2020-06-02 18:36
 **/
public class QuartzBean {
 
  /** 任务id */
  private String id;
 
  /** 任务名称 */
  private String jobName;
 
  /** 任务组 */
  private String jobGroup;
 
  /** 任务执行类 */
  private String jobClass;
 
  /** 任务状态 启动还是暂停*/
  private Integer status;
 
  /**
   * 任务开始时间
   */
  private Date startTime;
 
  /**
   * 任务循环间隔-单位:分钟
   */
  private Integer interval;
 
  /**
   * 任务结束时间
   */
  private Date endTime;
 
  /** 任务运行时间表达式 */
  private String cronExpression;
 
  private JobDataMap jobDataMap;
 
  public String getId() {
    return id;
  }
 
  public void setId(String id) {
    this.id = id;
  }
 
  public String getJobName() {
    return jobName;
  }
 
  public void setJobName(String jobName) {
    this.jobName = jobName;
  }
 
  public String getJobClass() {
    return jobClass;
  }
 
  public void setJobClass(String jobClass) {
    this.jobClass = jobClass;
  }
 
  public Integer getStatus() {
    return status;
  }
 
  public void setStatus(Integer status) {
    this.status = status;
  }
 
  public String getCronExpression() {
    return cronExpression;
  }
 
  public void setCronExpression(String cronExpression) {
    this.cronExpression = cronExpression;
  }
 
  public Date getStartTime() {
    return startTime;
  }
 
  public void setStartTime(Date startTime) {
    this.startTime = startTime;
  }
 
  public Integer getInterval() {
    return interval;
  }
 
  public void setInterval(Integer interval) {
    this.interval = interval;
  }
 
  public Date getEndTime() {
    return endTime;
  }
 
  public void setEndTime(Date endTime) {
    this.endTime = endTime;
  }
 
  public JobDataMap getJobDataMap() {
    return jobDataMap;
  }
 
  public void setJobDataMap(JobDataMap jobDataMap) {
    this.jobDataMap = jobDataMap;
  }
 
  public String getJobGroup() {
    return jobGroup;
  }
 
  public void setJobGroup(String jobGroup) {
    this.jobGroup = jobGroup;
  }
}

Service

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.framework.quartz.QuartzBean;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
 
/**
 * @program: QuartzJobService
 * @description:
 * @author: Yuwl
 * @create: 2020-07-21 17:00
 **/
@Service
public class QuartzJobService {
 
  @Autowired
  private Scheduler scheduler;
 
  /**
   * 创建定时任务Simple
   * quartzBean.getInterval()==null表示单次提醒,
   * 否则循环提醒(quartzBean.getEndTime()!=null)
   * @param quartzBean
   */
  public void createScheduleJobSimple(QuartzBean quartzBean) throws Exception{
    //获取到定时任务的执行类 必须是类的绝对路径名称
    //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
    Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
    // 构建定时任务信息
    JobDetail jobDetail = JobBuilder.newJob(jobClass)
        .withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
        .setJobData(quartzBean.getJobDataMap())
        .build();
    // 设置定时任务执行方式
    SimpleScheduleBuilder simpleScheduleBuilder = null;
    if (quartzBean.getInterval() == null) { //单次
      simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
    } else { //循环
      simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(quartzBean.getInterval());
    }
    // 构建触发器trigger
    Trigger trigger = null;
    if (quartzBean.getInterval() == null) { //单次
      trigger = TriggerBuilder.newTrigger()
          .withIdentity(quartzBean.getJobName(),ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
          .withSchedule(simpleScheduleBuilder)
          .startAt(quartzBean.getStartTime())
          .build();
    } else { //循环
      trigger = TriggerBuilder.newTrigger()
          .withIdentity(quartzBean.getJobName(),ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
          .withSchedule(simpleScheduleBuilder)
          .startAt(quartzBean.getStartTime())
          .endAt(quartzBean.getEndTime())
          .build();
    }
    scheduler.scheduleJob(jobDetail, trigger);
  }
 
  /**
   * 创建定时任务Cron
   * 定时任务创建之后默认启动状态
   * @param quartzBean 定时任务信息类
   * @throws Exception
   */
  public void createScheduleJobCron(QuartzBean quartzBean) throws Exception{
    //获取到定时任务的执行类 必须是类的绝对路径名称
    //定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
    Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(quartzBean.getJobClass());
    // 构建定时任务信息
    JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(quartzBean.getJobName()).setJobData(quartzBean.getJobDataMap()).build();
    // 设置定时任务执行方式
    CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
    // 构建触发器trigger
    CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(quartzBean.getJobName()).withSchedule(scheduleBuilder).build();
    scheduler.scheduleJob(jobDetail, trigger);
  }
 
  /**
   * 根据任务名称暂停定时任务
   * @param jobName 定时任务名称
   * @param jobGroup 任务组(没有分组传值null)
   * @throws Exception
   */
  public void pauseScheduleJob(String jobName,String jobGroup) throws Exception{
    JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    scheduler.pauseJob(jobKey);
  }
 
  /**
   * 根据任务名称恢复定时任务
   * @param jobName  定时任务名
   * @param jobGroup 任务组(没有分组传值null)
   * @throws SchedulerException
   */
  public void resumeScheduleJob(String jobName,String jobGroup) throws Exception {
    JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    scheduler.resumeJob(jobKey);
  }
 
  /**
   * 根据任务名称立即运行一次定时任务
   * @param jobName    定时任务名称
   * @param jobGroup 任务组(没有分组传值null)
   * @throws SchedulerException
   */
  public void runOnce(String jobName,String jobGroup) throws Exception{
    JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    scheduler.triggerJob(jobKey);
  }
 
  /**
   * 更新定时任务Simple
   * @param quartzBean 定时任务信息类
   * @throws SchedulerException
   */
  public void updateScheduleJobSimple(QuartzBean quartzBean) throws Exception {
    //获取到对应任务的触发器
    TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null);
    // 设置定时任务执行方式
    SimpleScheduleBuilder simpleScheduleBuilder = null;
    if (quartzBean.getInterval() == null) { //单次
      simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
    } else { //循环
      simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(quartzBean.getInterval());
    }
    // 构建触发器trigger
    Trigger trigger = null;
    if (quartzBean.getInterval() == null) { //单次
      trigger = TriggerBuilder.newTrigger()
          .withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
          .withSchedule(simpleScheduleBuilder)
          .startAt(quartzBean.getStartTime())
          .build();
    } else { //循环
      TriggerBuilder.newTrigger()
          .withIdentity(quartzBean.getJobName(), ObjectUtils.isNotEmpty(quartzBean.getJobGroup()) ?quartzBean.getJobGroup():null)
          .withSchedule(simpleScheduleBuilder)
          .startAt(quartzBean.getStartTime())
          .endAt(quartzBean.getEndTime())
          .build();
    }
    //重置对应的job
    scheduler.rescheduleJob(triggerKey, trigger);
  }
 
  /**
   * 更新定时任务Cron
   * @param quartzBean 定时任务信息类
   * @throws SchedulerException
   */
  public void updateScheduleJobCron(QuartzBean quartzBean) throws Exception {
    //获取到对应任务的触发器
    TriggerKey triggerKey = TriggerKey.triggerKey(quartzBean.getJobName());
    //设置定时任务执行方式
    CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzBean.getCronExpression());
    //重新构建任务的触发器trigger
    CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
    trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
    //重置对应的job
    scheduler.rescheduleJob(triggerKey, trigger);
  }
 
  /**
   * 根据定时任务名称从调度器当中删除定时任务
   * @param jobName  定时任务名称
   * @param jobGroup 任务组(没有分组传值null)
   * @throws SchedulerException
   */
  public void deleteScheduleJob(String jobName,String jobGroup) throws Exception {
    JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    scheduler.deleteJob(jobKey);
  }
 
  /**
   * 获取任务状态
   * @param jobName
   * @param jobGroup 任务组(没有分组传值null)
   * @return
   * (" BLOCKED ", " 阻塞 ");
   * ("COMPLETE", "完成");
   * ("ERROR", "出错");
   * ("NONE", "不存在");
   * ("NORMAL", "正常");
   * ("PAUSED", "暂停");
   */
  public String getScheduleJobStatus(String jobName,String jobGroup) throws Exception {
    TriggerKey triggerKey = TriggerKey.triggerKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    Trigger.TriggerState state = scheduler.getTriggerState(triggerKey);
    return state.name();
  }
 
  /**
   * 根据定时任务名称来判断任务是否存在
   * @param jobName  定时任务名称
   * @param jobGroup 任务组(没有分组传值null)
   * @throws SchedulerException
   */
  public Boolean checkExistsScheduleJob(String jobName,String jobGroup) throws Exception {
    JobKey jobKey = JobKey.jobKey(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    return scheduler.checkExists(jobKey);
  }
 
  /**
   * 根据任务組刪除定時任务
   * @param jobGroup 任务组
   * @throws SchedulerException
   */
  public Boolean deleteGroupJob(String jobGroup) throws Exception {
    GroupMatcher<JobKey> matcher = GroupMatcher.groupEquals(jobGroup);
    Set<JobKey> jobkeySet = scheduler.getJobKeys(matcher);
    List<JobKey> jobkeyList = new ArrayList<JobKey>();
    jobkeyList.addAll(jobkeySet);
    return scheduler.deleteJobs(jobkeyList);
  }
 
  /**
   * 根据任务組批量刪除定時任务
   * @param jobkeyList
   * @throws SchedulerException
   */
  public Boolean batchDeleteGroupJob(List<JobKey> jobkeyList) throws Exception {
    return scheduler.deleteJobs(jobkeyList);
  }
 
  /**
   * 根据任务組批量查询出jobkey
   * @param jobGroup 任务组
   * @throws SchedulerException
   */
  public void batchQueryGroupJob(List<JobKey> jobkeyList,String jobGroup) throws Exception {
    GroupMatcher<JobKey> matcher = GroupMatcher.groupEquals(jobGroup);
    Set<JobKey> jobkeySet = scheduler.getJobKeys(matcher);
    jobkeyList.addAll(jobkeySet);
  }
}

Job

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.quartz.demo.job
 
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
 
import java.util.Date;
 
/**
 * @program: job
 * @description:
 * @author: Yuwl
 * @create: 2020-06-02 18:07
 **/
@Component
public class MyTask extends QuartzJobBean {
  @Override
  protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
    JobKey jobKey = context.getJobDetail().getKey();
    JobDataMap map = context.getJobDetail().getJobDataMap();
    String userId = map.getString("userId");
    System.out.println("SimpleJob says: " + jobKey + ", userId: " + userId + " executing at " + new Date());
  }
}

Controller

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.framework.quartz.QuartzBean;
import com.ruoyi.framework.quartz.service.QuartzJobService;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.ParseException;
import java.util.Date;
 
/**
 * @program: JobController
 * @description:
 * @author: Yuwl
 * @create: 2020-07-21 17:08
 **/
@RestController
@RequestMapping("/api/quartz/")
public class JobController {
 
  @Autowired
  private QuartzJobService quartzJobService;
 
  //创建&启动
  @GetMapping("startSimpleJob")
  public String startSimpleJob() throws SchedulerException, ClassNotFoundException, ParseException {
    QuartzBean quartzBean = new QuartzBean();
    quartzBean.setJobClass("com.quartz.demo.job.MyTask");
    quartzBean.setJobName("job1");
    JobDataMap map = new JobDataMap();
    map.put("userId", "123456");
    quartzBean.setJobDataMap(map);
    Date now = new Date();
    quartzBean.setStartTime(DateUtils.addSeconds(now, 10));
    quartzBean.setInterval(10);
    quartzBean.setEndTime(DateUtils.addMinutes(now, 1));
    try {
      quartzJobService.createScheduleJobSimple(quartzBean);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return "startJob Success!";
  }
 
  /**
   * 创建cron Job
   * @param quartzBean
   * @return
   */
  @RequestMapping("/createCronJob")
  @ResponseBody
  public String createJob(QuartzBean quartzBean) {
    try {
      //进行测试所以写死
      quartzBean.setJobClass("com.quartz.demo.job.MyTask");
      quartzBean.setJobName("job1");
      quartzBean.setCronExpression("*/5 * * * * ?");
      quartzJobService.createScheduleJobCron(quartzBean);
    } catch (Exception e) {
      return "创建失败";
    }
    return "创建成功";
  }
 
  /**
   * 暂停job
   * @return
   */
  @RequestMapping(value = {"/pauseJob/{jobName}","/pauseJob/{jobName}/{jobGroup}"})
  @ResponseBody
  public String pauseJob(@PathVariable("jobName") String jobName,@PathVariable(required = false) String jobGroup) {
    try {
    quartzJobService.pauseScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    } catch (Exception e) {
      return "暂停失败";
    }
    return "暂停成功";
  }
 
  @RequestMapping(value = {"/resume/{jobName}","/resume/{jobName}/{jobGroup}"})
  @ResponseBody
  public String resume(@PathVariable("jobName") String jobName,@PathVariable(required = false) String jobGroup) {
    try {
  quartzJobService.resumeScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    } catch (Exception e) {
      return "启动失败";
    }
    return "启动成功";
  }
 
  @RequestMapping(value = {"/delete/{jobName}","/delete/{jobName}/{jobGroup}"})
  public String delete(@PathVariable("jobName") String jobName,@PathVariable(required = false) String jobGroup) {
    try {
      quartzJobService.deleteScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    } catch (Exception e) {
      return "删除失败";
    }
    return "删除成功";
  }
 
  @RequestMapping(value = {"/check/{jobName}","/check/{jobName}/{jobGroup}"})
  public String check(@PathVariable("jobName") String jobName,@PathVariable(required = false) String jobGroup) {
    try {
      if(quartzJobService.checkExistsScheduleJob(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null)){
        return "存在定时任务:"+jobName;
      }else{
        return "不存在定时任务:"+jobName;
      }
    } catch (Exception e) {
      return "查询任务失败";
    }
  }
 
  @RequestMapping(value = {"/status/{jobName}","/status/{jobName}/{jobGroup}"})
  @ResponseBody
  public String status(@PathVariable("jobName") String jobName,@PathVariable(required = false) String jobGroup) {
    try {
      return quartzJobService.getScheduleJobStatus(jobName,ObjectUtils.isNotEmpty(jobGroup) ?jobGroup:null);
    } catch (Exception e) {
      return "获取状态失败";
    }
    //return "获取状态成功";
  }
 
}

测试
http://localhost:8080/api/quartz/startSimpleJob

到此这篇关于Springboot2.x+Quartz分布式集群的实现的文章就介绍到这了,更多相关Springboot2.x Quartz分布式集群内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.51cto.com/14942009/2536639