六、QUARTZ JDBC STORE
JDBCStore 概念
默认情况,Quartz的触发器,调度,任务等信息都是放在内存中的,叫做 RAMJobStore。 好处是快速,坏处是一旦系统重启,那么信息就丢失了,就得全部从头来过。
所以Quartz还提供了另一个方式,可以把这些信息存放在数据库做,叫做 JobStoreTX。 好处是就算系统重启了,目前运行到第几次了这些信息都是存放在数据库中的,那么就可以继续原来的步伐把计划任务无缝地继续做下去。 坏处就是性能上比内存慢一些,毕竟数据库读取总是要慢一些的。
所以Quartz还提供了另一个方式,可以把这些信息存放在数据库做,叫做 JobStoreTX。 好处是就算系统重启了,目前运行到第几次了这些信息都是存放在数据库中的,那么就可以继续原来的步伐把计划任务无缝地继续做下去。 坏处就是性能上比内存慢一些,毕竟数据库读取总是要慢一些的。
建表 sql
为了能够把相关信息存放进 mysql 数据库里,必须手动建立数据库和表,使用如下 脚本就行了。
注: 这里使用的数据库名称是 quartz
注: 这里使用的数据库名称是 quartz
|
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
|
DROP DATABASE IF EXISTS quartz;CREATE DATABASE quartz DEFAULT CHARACTER SET utf8;USE quartz;DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;DROP TABLE IF EXISTS QRTZ_LOCKS;DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;DROP TABLE IF EXISTS QRTZ_TRIGGERS;DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;DROP TABLE IF EXISTS QRTZ_CALENDARS;CREATE TABLE QRTZ_JOB_DETAILS ( SCHED_NAME VARCHAR(120) NOT NULL, JOB_NAME VARCHAR(100) NOT NULL, JOB_GROUP VARCHAR(100) NOT NULL, DESCRIPTION VARCHAR(250) NULL, JOB_CLASS_NAME VARCHAR(250) NOT NULL, IS_DURABLE VARCHAR(1) NOT NULL, IS_NONCONCURRENT VARCHAR(1) NOT NULL, IS_UPDATE_DATA VARCHAR(1) NOT NULL, REQUESTS_RECOVERY VARCHAR(1) NOT NULL, JOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP));CREATE TABLE QRTZ_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(100) NOT NULL, TRIGGER_GROUP VARCHAR(100) NOT NULL, JOB_NAME VARCHAR(100) NOT NULL, JOB_GROUP VARCHAR(100) NOT NULL, DESCRIPTION VARCHAR(250) NULL, NEXT_FIRE_TIME BIGINT(13) NULL, PREV_FIRE_TIME BIGINT(13) NULL, PRIORITY INTEGER NULL, TRIGGER_STATE VARCHAR(16) NOT NULL, TRIGGER_TYPE VARCHAR(8) NOT NULL, START_TIME BIGINT(13) NOT NULL, END_TIME BIGINT(13) NULL, CALENDAR_NAME VARCHAR(100) NULL, MISFIRE_INSTR SMALLINT(2) NULL, JOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP));CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(100) NOT NULL, TRIGGER_GROUP VARCHAR(100) NOT NULL, REPEAT_COUNT BIGINT(7) NOT NULL, REPEAT_INTERVAL BIGINT(12) NOT NULL, TIMES_TRIGGERED BIGINT(10) NOT NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP));CREATE TABLE QRTZ_CRON_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(100) NOT NULL, TRIGGER_GROUP VARCHAR(100) NOT NULL, CRON_EXPRESSION VARCHAR(100) NOT NULL, TIME_ZONE_ID VARCHAR(80), PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP));CREATE TABLE QRTZ_SIMPROP_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(100) NOT NULL, TRIGGER_GROUP VARCHAR(100) NOT NULL, STR_PROP_1 VARCHAR(512) NULL, STR_PROP_2 VARCHAR(512) NULL, STR_PROP_3 VARCHAR(512) NULL, INT_PROP_1 INT NULL, INT_PROP_2 INT NULL, LONG_PROP_1 BIGINT NULL, LONG_PROP_2 BIGINT NULL, DEC_PROP_1 NUMERIC(13,4) NULL, DEC_PROP_2 NUMERIC(13,4) NULL, BOOL_PROP_1 VARCHAR(1) NULL, BOOL_PROP_2 VARCHAR(1) NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP));CREATE TABLE QRTZ_BLOB_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_NAME VARCHAR(100) NOT NULL, TRIGGER_GROUP VARCHAR(100) NOT NULL, BLOB_DATA BLOB NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP));CREATE TABLE QRTZ_CALENDARS ( SCHED_NAME VARCHAR(120) NOT NULL, CALENDAR_NAME VARCHAR(100) NOT NULL, CALENDAR BLOB NOT NULL, PRIMARY KEY (SCHED_NAME,CALENDAR_NAME));CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( SCHED_NAME VARCHAR(120) NOT NULL, TRIGGER_GROUP VARCHAR(100) NOT NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP));CREATE TABLE QRTZ_FIRED_TRIGGERS ( SCHED_NAME VARCHAR(120) NOT NULL, ENTRY_ID VARCHAR(95) NOT NULL, TRIGGER_NAME VARCHAR(100) NOT NULL, TRIGGER_GROUP VARCHAR(100) NOT NULL, INSTANCE_NAME VARCHAR(100) NOT NULL, FIRED_TIME BIGINT(13) NOT NULL, SCHED_TIME BIGINT(13) NOT NULL, PRIORITY INTEGER NOT NULL, STATE VARCHAR(16) NOT NULL, JOB_NAME VARCHAR(100) NULL, JOB_GROUP VARCHAR(100) NULL, IS_NONCONCURRENT VARCHAR(1) NULL, REQUESTS_RECOVERY VARCHAR(1) NULL, PRIMARY KEY (SCHED_NAME,ENTRY_ID));CREATE TABLE QRTZ_SCHEDULER_STATE ( SCHED_NAME VARCHAR(120) NOT NULL, INSTANCE_NAME VARCHAR(100) NOT NULL, LAST_CHECKIN_TIME BIGINT(13) NOT NULL, CHECKIN_INTERVAL BIGINT(13) NOT NULL, PRIMARY KEY (SCHED_NAME,INSTANCE_NAME));CREATE TABLE QRTZ_LOCKS ( SCHED_NAME VARCHAR(120) NOT NULL, LOCK_NAME VARCHAR(40) NOT NULL, PRIMARY KEY (SCHED_NAME,LOCK_NAME));commit; |
配置文件
在src下新建 quartz.properties 配置文件,里面指定使用 JobStoreTX 方式管理任务。 并且指定链接数据库的账号密码等信息
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.tablePrefix = QRTZ_org.quartz.scheduler.instanceName = MySchedulerorg.quartz.threadPool.threadCount = 3org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegateorg.quartz.jobStore.tablePrefix = QRTZ_org.quartz.jobStore.dataSource = mysqlDatabaseorg.quartz.dataSource.mysqlDatabase.driver = com.mysql.jdbc.Driverorg.quartz.dataSource.mysqlDatabase.URL = jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8org.quartz.dataSource.mysqlDatabase.user = rootorg.quartz.dataSource.mysqlDatabase.password = adminorg.quartz.dataSource.mysqlDatabase.maxConnections = 5 |
MailJob
这个和以前的一样,没什么变化
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.how2java;import java.text.SimpleDateFormat;import java.util.Date;import org.quartz.DisallowConcurrentExecution;import org.quartz.Job;import org.quartz.JobDetail;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;@DisallowConcurrentExecutionpublic class MailJob implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { JobDetail detail = context.getJobDetail(); String email = detail.getJobDataMap().getString("email"); SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); String now = sdf.format(new Date()); System.out.printf("给邮件地址 %s 发出了一封定时邮件, 当前时间是: %s (%s)%n" ,email, now,context.isRecovering()); }} |
TestQuartz
新增加了一个resumeJobFromDatabase 方法,当使用原来的方式增加任务报异常的时候,就直接从数据库重跑任务。
任务的触发也调整成了15秒一次,总共11次。
任务的触发也调整成了15秒一次,总共11次。
|
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
|
package com.how2java;import static org.quartz.JobBuilder.newJob;import static org.quartz.SimpleScheduleBuilder.simpleSchedule;import static org.quartz.TriggerBuilder.newTrigger;import org.quartz.JobDetail;import org.quartz.ObjectAlreadyExistsException;import org.quartz.Scheduler;import org.quartz.SchedulerException;import org.quartz.Trigger;import org.quartz.impl.StdSchedulerFactory;public class TestQuartz { public static void main(String[] args) throws Exception { try { assginNewJob(); } catch (ObjectAlreadyExistsException e) { System.err.println("发现任务已经在数据库存在了,直接从数据库里运行:"+ e.getMessage()); // TODO Auto-generated catch block resumeJobFromDatabase(); } } private static void resumeJobFromDatabase() throws Exception { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); // 等待200秒,让前面的任务都执行完了之后,再关闭调度器 Thread.sleep(200000); scheduler.shutdown(true); } private static void assginNewJob() throws SchedulerException, InterruptedException { // 创建调度器 Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // 定义一个触发器 Trigger trigger = newTrigger().withIdentity("trigger1", "group1") // 定义名称和所属的租 .startNow() .withSchedule(simpleSchedule().withIntervalInSeconds(15) // 每隔15秒执行一次 .withRepeatCount(10)) // 总共执行11次(第一次执行不基数) .build(); // 定义一个JobDetail JobDetail job = newJob(MailJob.class) // 指定干活的类MailJob .withIdentity("mailjob1", "mailgroup") // 定义任务名称和分组 .usingJobData("email", "admin@10086.com") // 定义属性 .build(); // 调度加入这个job scheduler.scheduleJob(job, trigger); // 启动 scheduler.start(); // 等待20秒,让前面的任务都执行完了之后,再关闭调度器 Thread.sleep(20000); scheduler.shutdown(true); }} |
运行 TestQuartz,为了看到如图所示的效果,要按照如下步骤进行:
1. 先运行一次,是不会看到红色的,因为此时数据库里还没有任务,会顺利执行
2. 经过20秒,自动结束。此时任务还未运行完毕(任务设计是总共10次,间隔15秒一次)。
3. 不用修改代码,再次执行,就会看到红色的字样,表示试图向数据库添加任务,但是发现任务已经在数据库里已经存在了,那么这个时候调度就会自动运行数据库里的任务,从而达到系统重启后自动衔接的效果
注: 项目需要用到的mysql 连接 jar 包已经包含在可运行项目里了
1. 先运行一次,是不会看到红色的,因为此时数据库里还没有任务,会顺利执行
2. 经过20秒,自动结束。此时任务还未运行完毕(任务设计是总共10次,间隔15秒一次)。
3. 不用修改代码,再次执行,就会看到红色的字样,表示试图向数据库添加任务,但是发现任务已经在数据库里已经存在了,那么这个时候调度就会自动运行数据库里的任务,从而达到系统重启后自动衔接的效果
注: 项目需要用到的mysql 连接 jar 包已经包含在可运行项目里了
浙公网安备 33010602011771号