一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Springboot2.x+Quartz分布式集群的實現

Springboot2.x+Quartz分布式集群的實現

2020-09-24 00:33yuwl01 Java教程

這篇文章主要介紹了Springboot2.x+Quartz分布式集群的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

生產環境一般都是多節點高可用,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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美在线一级视频 | 免费观看二十女人一摸是水 | 亚洲精品AV无码喷奶水糖心 | 韩国日本香港毛片免费 | 国产亚洲成归v人片在线观看 | 亚洲国产成人久久综合一区77 | 强制高h| 午夜视频一区二区 | 成人伊人青草久久综合网破解版 | 国产精品高清一区二区三区 | 唯美清纯 自拍偷 | 色婷婷婷婷 | 久久最新地址获取 | 视频大全在线观看免费 | 果冻传媒天美传媒网址入口 | 青青草一区二区免费精品 | 91在线老师啪国自产 | 黑人好大好硬好深好爽想要h | 亚洲男人天堂网址 | 激情影院免费观看 | 亚洲国产成人精品不卡青青草原 | 久久91精品国产91久久户 | aaa一级最新毛片 | 乖女的嫩奶水h文孕妇 | 日本中文字幕在线视频 | 共妻高h | 娇妻与公陈峰姚瑶小说在线阅读 | 国产啪精品视频网给免丝袜 | 国内精品视频一区二区三区八戒 | 日本精品一卡二卡≡卡四卡 | 7mav视频| 精品国产一区二区 | 久久精品国产视频澳门 | 亚洲精品卡1卡二卡3卡四卡 | 视频一区国产精戏刘婷30 | 久久亚洲一级α片 | jizz农村野外jizz农民 | 国产重口老太伦 | 二次元美女扒开内裤露尿口 | 18性夜影院午夜寂寞影院免费 | 成年人在线视频观看 |