Quartz任务调度(3)存储与持久化操作配置详细解析
2016年03月26日 22:06:00
阅读数:8913

内存存储RAMJobStore

Quartz默认使用RAMJobStore,它的优点是速度。因为所有的 Scheduler 信息都保存在计算机内存中,访问这些数据随着电脑而变快。而无须访问数据库或IO等操作,但它的缺点是将 Job 和 Trigger 信息存储在内存中的。因而我们每次重启程序,Scheduler 的状态,包括 Job 和 Trigger 信息都丢失了。 
Quartz 的内存 Job 存储的能力是由一个叫做 org.quartz.simple.RAMJobStore 类提供。在我们的quartz-2.x.x.jar包下的org.quartz包下即存储了我们的默认配置quartz.properties。打开这个配置文件,我们会看到如下信息


# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#

org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true

org.quartz.jobStore.misfireThreshold: 60000

org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore #这里默认使用RAMJobStore
 
1
# Default Properties file for use by StdSchedulerFactory
2
# to create a Quartz Scheduler Instance, if a different
3
# properties file is not explicitly specified.
4
#
5
6
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
7
org.quartz.scheduler.rmi.export: false
8
org.quartz.scheduler.rmi.proxy: false
9
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
10
11
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
12
org.quartz.threadPool.threadCount: 10
13
org.quartz.threadPool.threadPriority: 5
14
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
15
16
org.quartz.jobStore.misfireThreshold: 60000
17
18
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore #这里默认使用RAMJobStore
19

持久性JobStore

Quartz 提供了两种类型的持久性 JobStore,为JobStoreTX和JobStoreCMT,其中: 
1. JobStoreTX为独立环境中的持久性存储,它设计为用于独立环境中。这里的 “独立”,我们是指这样一个环境,在其中不存在与应用容器的事物集成。这里并不意味着你不能在一个容器中使用 JobStoreTX,只不过,它不是设计来让它的事特受容器管理。区别就在于 Quartz 的事物是否要参与到容器的事物中去。 
2. JobStoreCMT 为程序容器中的持久性存储,它设计为当你想要程序容器来为你的 JobStore 管理事物时,并且那些事物要参与到容器管理的事物边界时使用。它的名字明显是来源于容器管理的事物(Container Managed Transactions (CMT))。

持久化配置步骤

要将JobDetail等信息持久化我们的数据库中,我们可按一下步骤操作:

1. 配置数据库

在 /docs/dbTables 目录下存放了几乎所有数据库的的SQL脚本,这里的 是解压 Quartz 分发包后的目录。我们使用常用mysql数据库,下面是示例sql脚本代码

#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#

DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;


CREATE TABLE QRTZ_JOB_DETAILS
  (
    SCHED_NAME VARCHAR(80) NOT NULL,
    JOB_NAME  VARCHAR(100) NOT NULL,
    JOB_GROUP VARCHAR(100) NOT NULL,
    DESCRIPTION VARCHAR(100) NULL,
    JOB_CLASS_NAME   VARCHAR(100) 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(80) 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(100) 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(80) 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(80) 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(80) NOT NULL,
    TRIGGER_NAME VARCHAR(100) NOT NULL,
    TRIGGER_GROUP VARCHAR(100) NOT NULL,
    STR_PROP_1 VARCHAR(120) NULL,
    STR_PROP_2 VARCHAR(120) NULL,
    STR_PROP_3 VARCHAR(120) 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(80) 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(80) 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(80) NOT NULL,
    TRIGGER_GROUP  VARCHAR(100) NOT NULL,
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);

CREATE TABLE QRTZ_FIRED_TRIGGERS
  (
    SCHED_NAME VARCHAR(80) 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(80) 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(80) NOT NULL,
    LOCK_NAME  VARCHAR(40) NOT NULL,
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);

commit;
 
1
#
2
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
3
#
4
# PLEASE consider using mysql with innodb tables to avoid locking issues
5
#
6
# In your Quartz properties file, you'll need to set 
7
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
8
#
9
10
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
11
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
12
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
13
DROP TABLE IF EXISTS QRTZ_LOCKS;
14
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
15
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
16
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
17
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
18
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
19
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
20
DROP TABLE IF EXISTS QRTZ_CALENDARS;
21
22
23
CREATE TABLE QRTZ_JOB_DETAILS
24
  (
25
    SCHED_NAME VARCHAR(80) NOT NULL,
26
    JOB_NAME  VARCHAR(100) NOT NULL,
27
    JOB_GROUP VARCHAR(100) NOT NULL,
28
    DESCRIPTION VARCHAR(100) NULL,
29
    JOB_CLASS_NAME   VARCHAR(100) NOT NULL,
30
    IS_DURABLE VARCHAR(1) NOT NULL,
31
    IS_NONCONCURRENT VARCHAR(1) NOT NULL,
32
    IS_UPDATE_DATA VARCHAR(1) NOT NULL,
33
    REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
34
    JOB_DATA BLOB NULL,
35
    PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
36
);
37
38
CREATE TABLE QRTZ_TRIGGERS
39
  (
40
    SCHED_NAME VARCHAR(80) NOT NULL,
41
    TRIGGER_NAME VARCHAR(100) NOT NULL,
42
    TRIGGER_GROUP VARCHAR(100) NOT NULL,
43
    JOB_NAME  VARCHAR(100) NOT NULL,
44
    JOB_GROUP VARCHAR(100) NOT NULL,
45
    DESCRIPTION VARCHAR(100) NULL,
46
    NEXT_FIRE_TIME BIGINT(13) NULL,
47
    PREV_FIRE_TIME BIGINT(13) NULL,
48
    PRIORITY INTEGER NULL,
49
    TRIGGER_STATE VARCHAR(16) NOT NULL,
50
    TRIGGER_TYPE VARCHAR(8) NOT NULL,
51
    START_TIME BIGINT(13) NOT NULL,
52
    END_TIME BIGINT(13) NULL,
53
    CALENDAR_NAME VARCHAR(100) NULL,
54
    MISFIRE_INSTR SMALLINT(2) NULL,
55
    JOB_DATA BLOB NULL,
56
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
57
    FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
58
        REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
59
);
60
61
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
62
  (
63
    SCHED_NAME VARCHAR(80) NOT NULL,
64
    TRIGGER_NAME VARCHAR(100) NOT NULL,
65
    TRIGGER_GROUP VARCHAR(100) NOT NULL,
66
    REPEAT_COUNT BIGINT(7) NOT NULL,
67
    REPEAT_INTERVAL BIGINT(12) NOT NULL,
68
    TIMES_TRIGGERED BIGINT(10) NOT NULL,
69
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
70
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
71
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
72
);
73
74
CREATE TABLE QRTZ_CRON_TRIGGERS
75
  (
76
    SCHED_NAME VARCHAR(80) NOT NULL,
77
    TRIGGER_NAME VARCHAR(100) NOT NULL,
78
    TRIGGER_GROUP VARCHAR(100) NOT NULL,
79
    CRON_EXPRESSION VARCHAR(100) NOT NULL,
80
    TIME_ZONE_ID VARCHAR(80),
81
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
82
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
83
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
84
);
85
86
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
87
  (          
88
    SCHED_NAME VARCHAR(80) NOT NULL,
89
    TRIGGER_NAME VARCHAR(100) NOT NULL,
90
    TRIGGER_GROUP VARCHAR(100) NOT NULL,
91
    STR_PROP_1 VARCHAR(120) NULL,
92
    STR_PROP_2 VARCHAR(120) NULL,
93
    STR_PROP_3 VARCHAR(120) NULL,
94
    INT_PROP_1 INT NULL,
95
    INT_PROP_2 INT NULL,
96
    LONG_PROP_1 BIGINT NULL,
97
    LONG_PROP_2 BIGINT NULL,
98
    DEC_PROP_1 NUMERIC(13,4) NULL,
99
    DEC_PROP_2 NUMERIC(13,4) NULL,
100
    BOOL_PROP_1 VARCHAR(1) NULL,
101
    BOOL_PROP_2 VARCHAR(1) NULL,
102
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
103
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) 
104
    REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
105
);
106
107
CREATE TABLE QRTZ_BLOB_TRIGGERS
108
  (
109
    SCHED_NAME VARCHAR(80) NOT NULL,
110
    TRIGGER_NAME VARCHAR(100) NOT NULL,
111
    TRIGGER_GROUP VARCHAR(100) NOT NULL,
112
    BLOB_DATA BLOB NULL,
113
    PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
114
    FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
115
        REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
116
);
117
118
CREATE TABLE QRTZ_CALENDARS
119
  (
120
    SCHED_NAME VARCHAR(80) NOT NULL,
121
    CALENDAR_NAME  VARCHAR(100) NOT NULL,
122
    CALENDAR BLOB NOT NULL,
123
    PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
124
);
125
126
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
127
  (
128
    SCHED_NAME VARCHAR(80) NOT NULL,
129
    TRIGGER_GROUP  VARCHAR(100) NOT NULL, 
130
    PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
131
);
132
133
CREATE TABLE QRTZ_FIRED_TRIGGERS
134
  (
135
    SCHED_NAME VARCHAR(80) NOT NULL,
136
    ENTRY_ID VARCHAR(95) NOT NULL,
137
    TRIGGER_NAME VARCHAR(100) NOT NULL,
138
    TRIGGER_GROUP VARCHAR(100) NOT NULL,
139
    INSTANCE_NAME VARCHAR(100) NOT NULL,
140
    FIRED_TIME BIGINT(13) NOT NULL,
141
    SCHED_TIME BIGINT(13) NOT NULL,
142
    PRIORITY INTEGER NOT NULL,
143
    STATE VARCHAR(16) NOT NULL,
144
    JOB_NAME VARCHAR(100) NULL,
145
    JOB_GROUP VARCHAR(100) NULL,
146
    IS_NONCONCURRENT VARCHAR(1) NULL,
147
    REQUESTS_RECOVERY VARCHAR(1) NULL,
148
    PRIMARY KEY (SCHED_NAME,ENTRY_ID)
149
);
150
151
CREATE TABLE QRTZ_SCHEDULER_STATE
152
  (
153
    SCHED_NAME VARCHAR(80) NOT NULL,
154
    INSTANCE_NAME VARCHAR(100) NOT NULL,
155
    LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
156
    CHECKIN_INTERVAL BIGINT(13) NOT NULL,
157
    PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
158
);
159
160
CREATE TABLE QRTZ_LOCKS
161
  (
162
    SCHED_NAME VARCHAR(80) NOT NULL,
163
    LOCK_NAME  VARCHAR(40) NOT NULL, 
164
    PRIMARY KEY (SCHED_NAME,LOCK_NAME)
165
);
166
167
commit;
168

其中各表的含义如下所示:

QRTZ_CALENDARS以 Blob 类型存储 Quartz 的 Calendar 信息
QRTZ_CRON_TRIGGERS存储 Cron Trigger,包括 Cron 表达式和时区信息
QRTZ_FIRED_TRIGGERS存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
QRTZ_PAUSED_TRIGGER_GRPS存储已暂停的 Trigger 组的信息
QRTZ_SCHEDULER_STATE存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)
QRTZ_LOCKS存储程序的非观锁的信息(假如使用了悲观锁)
QRTZ_JOB_DETAILS存储每一个已配置的 Job 的详细信息
QRTZ_JOB_LISTENERS存储有关已配置的 JobListener 的信息
QRTZ_SIMPLE_TRIGGERS存储简单的 Trigger,包括重复次数,间隔,以及已触的次数
QRTZ_BLOG_TRIGGERS Trigger作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
QRTZ_TRIGGER_LISTENERS存储已配置的 TriggerListener 的信息
QRTZ_TRIGGERS存储已配置的 Trigger 的信息

2. 使用JobStoreTX

  1. 首先,我们需要在我们的属性文件中表明使用JobStoreTX: 
    org.quartz.jobStore.class = org.quartz.ompl.jdbcjobstore.JobStoreTX
  2. 然后我们需要配置能理解不同数据库系统中某一特定方言的驱动代理:
Cloudscape/Derbyorg.quartz.impl.jdbcjobstore.CloudscapeDelegate
DB2 (version 6.x)org.quartz.impl.jdbcjobstore.DB2v6Delegate
DB2 (version 7.x)org.quartz.impl.jdbcjobstore.DB2v7Delegate
DB2 (version 8.x)org.quartz.impl.jdbcjobstore.DB2v8Delegate
HSQLDBorg.quartz.impl.jdbcjobstore.PostgreSQLDelegate
MS SQL Serverorg.quartz.impl.jdbcjobstore.MSSQLDelegate
Pointbaseorg.quartz.impl.jdbcjobstore.PointbaseDelegate
PostgreSQLorg.quartz.impl.jdbcjobstore.PostgreSQLDelegate
(WebLogic JDBC Driver)org.quartz.impl.jdbcjobstore.WebLogicDelegate
(WebLogic 8.1 with Oracle)org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate
Oracleorg.quartz.impl.jdbcjobstore.oracle.OracleDelegate

如果我们的数据库平台没在上面列出,那么最好的选择就是,直接使用标准的 JDBC 代理 org.quartz.impl.jdbcjobstore.StdDriverDelegate 就能正常的工作。

  1. 以下是一些相关常用的配置属性及其说明:
org.quartz.jobStore.dataSource用于 quartz.properties 中数据源的名称
org.quartz.jobStore.tablePrefixQRTZ_指定用于 Scheduler 的一套数据库表名的前缀。假如有不同的前缀,Scheduler 就能在同一数据库中使用不同的表。
org.quartz.jobStore.userPropertiesFalse“use properties” 标记指示着持久性 JobStore 所有在 JobDataMap 中的值都是字符串,因此能以 名-值 对的形式存储,而不用让更复杂的对象以序列化的形式存入 BLOB 列中。这样会更方便,因为让你避免了发生于序列化你的非字符串的类到 BLOB 时的有关类版本的问题。
org.quartz.jobStore.misfireThreshold60000在 Trigger 被认为是错过触发之前,Scheduler 还容许 Trigger 通过它的下次触发时间的毫秒数。默认值(假如你未在配置中存在这一属性条目) 是 60000(60 秒)。这个不仅限于 JDBC-JobStore;它也可作为 RAMJobStore 的参数
org.quartz.jobStore.isClusteredFalse设置为 true 打开集群特性。如果你有多个 Quartz 实例在用同一套数据库时,这个属性就必须设置为 true。
org.quartz.jobStore.clusterCheckinInterval15000设置一个频度(毫秒),用于实例报告给集群中的其他实例。这会影响到侦测失败实例的敏捷度。它只用于设置了 isClustered 为 true 的时候。
org.quartz.jobStore.maxMisfiresToHandleAtATime20这是 JobStore 能处理的错过触发的 Trigger 的最大数量。处理太多(超过两打) 很快会导致数据库表被锁定够长的时间,这样就妨碍了触发别的(还未错过触发) trigger 执行的性能。
org.quartz.jobStore.dontSetAutoCommitFalseFalse设置这个参数为 true 会告诉 Quartz 从数据源获取的连接后不要调用它的 setAutoCommit(false) 方法。这在少些情况下是有帮助的,比如假如你有这样一个驱动,它会抱怨本来就是关闭的又来调用这个方法。这个属性默认值是 false,因为大多数的驱动都要求调用 setAutoCommit(false)。
org.quartz.jobStore.selectWithLockSQLSELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE这必须是一个从 LOCKS 表查询一行并对这行记录加锁的 SQL 语句。假如未设置,默认值就是 SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE,这能在大部分数据库上工作。{0} 会在运行期间被前面你配置的 TABLE_PREFIX 所替换。
org.quartz.jobStore.txIsolationLevelSerializableFalse值为 true 时告知 Quartz(当使用 JobStoreTX 或 CMT) 调用 JDBC 连接的 setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE) 方法。这有助于阻止某些数据库在高负载和长时间事物时锁的超时。

4. 我们还需要配置Datasource 属性

org.quartz.dataSource.NAME.driverJDBC 驱动类的全限名
org.quartz.dataSource.NAME.URL连接到你的数据库的 URL(主机,端口等)
org.quartz.dataSource.NAME.user用于连接你的数据库的用户名
org.quartz.dataSource.NAME.password用于连接你的数据库的密码
org.quartz.dataSource.NAME.maxConnectionsDataSource 在连接接中创建的最大连接数
org.quartz.dataSource.NAME.validationQuary一个可选的 SQL 查询字串,DataSource 用它来侦测并替换失败/断开的连接。例如,Oracle 用户可选用 select table_name from user_tables,这个查询应当永远不会失败,除非直的就是连接不上了。

下面是我们的一个quartz.properties属性文件配置实例:

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myDS

org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password = root
org.quartz.dataSource.myDS.maxConnections =5
 
 
1
org.quartz.scheduler.instanceName = MyScheduler
2
org.quartz.threadPool.threadCount = 3
3
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
4
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
5
org.quartz.jobStore.tablePrefix = QRTZ_
6
org.quartz.jobStore.dataSource = myDS
7
8
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
9
org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8
10
org.quartz.dataSource.myDS.user = root
11
org.quartz.dataSource.myDS.password = root
12
org.quartz.dataSource.myDS.maxConnections =5
13
 

配置好quartz.properties属性文件后,我们只要**将它放在类路径下,然后运行我们的程序,即可覆盖在quartz.jar包中默认的配置文件

3. 测试

编写我们的测试文件,我们的测试环境是在quartz-2.2.2版本下进行的。下面的测试用例引用了上篇文章 ,关于Quartz的快速入门配置可移步参考这篇文章。

public class pickNewsJob implements Job {

    @Override
    public void execute(JobExecutionContext jec) throws JobExecutionException {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        System.out.println("在"+sdf.format(new Date())+"扒取新闻");
    }

    public static void main(String args[]) throws SchedulerException {
        JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class)
                .withIdentity("job1", "jgroup1").build();
        SimpleTrigger simpleTrigger = TriggerBuilder
                .newTrigger()
                .withIdentity("trigger1")
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2))
                .startNow()
                .build();

        //创建scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.scheduleJob(jobDetail, simpleTrigger);
        scheduler.start();
    }
}
 
1
public class pickNewsJob implements Job {
2
3
    @Override
4
    public void execute(JobExecutionContext jec) throws JobExecutionException {
5
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
6
        System.out.println("在"+sdf.format(new Date())+"扒取新闻");
7
    }
8
9
    public static void main(String args[]) throws SchedulerException {
10
        JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class)
11
                .withIdentity("job1", "jgroup1").build();
12
        SimpleTrigger simpleTrigger = TriggerBuilder
13
                .newTrigger()
14
                .withIdentity("trigger1")
15
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2))
16
                .startNow()
17
                .build();
18
19
        //创建scheduler
20
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
21
        Scheduler scheduler = schedulerFactory.getScheduler();
22
        scheduler.scheduleJob(jobDetail, simpleTrigger);
23
        scheduler.start();
24
    }
25
}
26

执行测试方法,能看到控制台打印如下日志信息,关注红色部分,更注意其中的粗体部分,是我们quartz调用数据库的一些信息:

4. 拓展测试

我们再次运行测试方法,然后马上中断程序,查询我们数据库,会看到如下内容: 
SELECT * FROM QRTZ_SIMPLE_TRIGGERS; 
+————-+————–+—————+————–+—————–+—————–+ 
| SCHED_NAME | TRIGGER_NAME | TRIGGER_GROUP | REPEAT_COUNT | REPEAT_INTERVAL | TIMES_TRIGGERED | 
+————-+————–+—————+————–+—————–+—————–+ 
| MyScheduler | trigger1 | DEFAULT | 9 | 2000 | 1 | 
+————-+————–+—————+————–+—————–+—————–+ 
1 row in set (0.00 sec)

然后我们再运行程序,发现报错了。 
org.quartz.ObjectAlreadyExistsException: Unable to store Job : ‘jgroup1.job1’, because one already exists with this identification. 
一般的,在我们的任务调度前,会先将相关的任务持久化到数据库中,然后调用完在删除记录,这里在程序开始试图将任务信息持久化到数据库时,显然和(因为我们之前中断操作导致)数据库中存在的记录起了冲突。

5. 恢复异常中断的任务

这个时候,我们可以选择修改我们的job名和组名和triiger名,然后再运行我们的程序。查看控制台打印的信息部分展示如下:

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
    Scheduler scheduler = schedulerFactory.getScheduler();
    // ①获取调度器中所有的触发器组
    List<String> triggerGroups = scheduler.getTriggerGroupNames();
    // ②重新恢复在tgroup1组中,名为trigger1触发器的运行
    for (int i = 0; i < triggerGroups.size(); i++) {//这里使用了两次遍历,针对每一组触发器里的每一个触发器名,和每一个触发组名进行逐次匹配
        List<String> triggers = scheduler.getTriggerGroupNames();
        for (int j = 0; j < triggers.size(); j++) {
            Trigger tg = scheduler.getTrigger(new TriggerKey(triggers
                    .get(j), triggerGroups.get(i)));
            // ②-1:根据名称判断
            if (tg instanceof SimpleTrigger
                    && tg.getDescription().equals("jgroup1.DEFAULT")) {//由于我们之前测试没有设置触发器所在组,所以默认为DEFAULT
                // ②-1:恢复运行
                scheduler.resumeJob(new JobKey(triggers.get(j),
                        triggerGroups.get(i)));
            }
        }
    }
    scheduler.start();
}
 
1
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
2
    Scheduler scheduler = schedulerFactory.getScheduler();
3
    // ①获取调度器中所有的触发器组
4
    List<String> triggerGroups = scheduler.getTriggerGroupNames();
5
    // ②重新恢复在tgroup1组中,名为trigger1触发器的运行
6
    for (int i = 0; i < triggerGroups.size(); i++) {//这里使用了两次遍历,针对每一组触发器里的每一个触发器名,和每一个触发组名进行逐次匹配
7
        List<String> triggers = scheduler.getTriggerGroupNames();
8
        for (int j = 0; j < triggers.size(); j++) {
9
            Trigger tg = scheduler.getTrigger(new TriggerKey(triggers
10
                    .get(j), triggerGroups.get(i)));
11
            // ②-1:根据名称判断
12
            if (tg instanceof SimpleTrigger
13
                    && tg.getDescription().equals("jgroup1.DEFAULT")) {//由于我们之前测试没有设置触发器所在组,所以默认为DEFAULT
14
                // ②-1:恢复运行
15
                scheduler.resumeJob(new JobKey(triggers.get(j),
16
                        triggerGroups.get(i)));
17
            }
18
        }
19
    }
20
    scheduler.start();
21
}
22

调用此方法,我们在数据库中异常中断任务记录就会被读取执行,然后被删除掉。






01-06 13:53
查看更多