Quartz Tutorial 8 - Job Stores

Quartz Tutorial 8 - Job Stores

Quartz Tutorial 8 - Job Stores

JobStore用于保持对你交给调度器的“工作数据”的持续跟踪,这些数据包括:作业、触发器、日历等等。选择合适的JobStore对你的Quartz调度器实例来说,是相当重要的一步。当然,你了解了他们之间的差异之后做出选择还是很简单的。你需要通过属性文件(或对象)告知SchedulerFactory你需要用到的JobStore(及对它的相关配置),然后SchedulerFactory生成一个调度器实例。

绝不要在代码中直接使用JobStore实例,虽然很多人出于各种各样的原因已经尝试过了。JobStore是Quartz在后台自己使用的。你只需要告知Quartz(通过配置信息)你要用到哪个JobStore,然后你只需要在代码中使用Scheduler接口就好。

RAMJobStore

RAMJobStore是最简单的JobStore了,它也是性能最好的了(在CPU时间方面)。RAMJobStore将它所有的数据都放在内存里,也因此而得名。这也是为何它为何如此轻量快速,也最容易配置。但缺点是,一旦你的应用结束(或者崩溃),所有调度相关信息都没了,这也意味着RAMJobStore不能赋予它的作业和触发器“非易失性”。对有些程序来说这不是什么问题,甚至是期望行为,但对有些程序来说,这完全不可接受。

要使用RAMJobStore(假定你正在用StdSchedulerFactory),你只需要将你用于配置Quartz处将JobStore类属性设置为org.quartz.simpl.RAMJobStore,如下所示

1
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

好了,除此之外没有任何需要配置的地方了。

JDBCJobStore

顾名思义,JDBCJobStore将它所有的数据存储到了数据库里,然后通过JDBC访问。因此相对于RAMJobStore,对它的配置就有些麻烦,当然也没有那么快了。然而它的性能倒也没有特别坏,尤其是你在数据库表中在主键上建立了索引。在正常的现代集群中,调度器和数据库之间链接正常,那么获取和更新一个正在触发的触发器状态的时间一般小于10毫秒。

JDBCJobStore几乎可以和所有数据库一起使用,例如Oracle、PostgreSQL、MySQL、MS SQL Server、 HSQLDB和DB2。要使用JDBCJobStore,你首先要在数据库中创建Quartz要用的那些表。在Quartz分支的docs/dbTables文件夹下你能找到建表的SQL脚本。如果里面没有用于你的数据库类型的脚本,你只需要打开任何一个,然后改改。有一点要特别提出来,所有以QRTZ_开头的表名(例如QRTZ_TRIGGERS QRTZ_JOB_DETAIL),这些前缀实际上可以是任意的。只要你在Quartz的配置文件里告知了JDBCJobStore你用了啥前缀就好。当你想在一个数据库中为不同的调度器实例创建不同的表的时候,这个特性还是很有用的。

表建完了之后,在配置和启动JDBCJobStore之前你还有个“重大决定”需要做出:你需要使用哪种事务。如果你不需要将调度命令(例如添加、移除触发器)束缚于于其它事务,那么你可以让Quartz用JobStoreTX作为你的JobStore来管理事务,这也是大部分人的选择。

如果你需要让Quartz与其他事务一起工作(例如在一个J2EE应用服务器内部),那你应该用JobStoreCMT,这样Quartz将会让应用服务器容器来管理事务。

最后一部分就是设置数据源,这样JDBCJobStore就能获取与数据库的连接了。数据源是在Quartz的配置文件里定义的。定义方式有多种,一种是让Quartz自己创建和管理-直接提供所有的连接信息。另一种是让Quartz使用它所在的应用服务器提供的数据源来干活-告知JDBCJobStore数据源的JDNI名字。要想知道配置文件的更多细节,去看看配置文件的例子,它在docs/config文件夹下。

假定你在使用StdSchedulerFactory,首先要在配置文件里将JobStore类属性写成org.quartz.impl.jdbcjobstore.JobStoreTX或者org.quartz.impl.jdbcjobstore.JobStoreCMT,这取决于你之前怎样决定的事务处理方式。

1
org.quartz.jobStore.class = org.quartz.impl.jbdcjobstore.JobStoreTX

接下来,你要选择一个驱动委托(DriverDelegate)给JobStore用。驱动委托是负责处理所有JDBC相关的工作,而且这也取决于你用什么数据库了。StdJDBCDelegate是使用“vanilla”JDBC代码(和SQL语句)来干活的委托。如果你没有配置这一项,那么Quartz就会使用这个。我们只为使用StdJDBCDelegate会出问题的数据库提供了专用委托(还真不少)。那些委托能够在org.quartz.imple.jdbcjobstore包或者它的子包发现。这些专用委托包括DB2v6Delegate(DB2 version6 及之前版本)、HSQLDBDelegate(用于 HSQLDB), MSSQLDelegate (用于 Microsoft SQLServer), PostgreSQLDelegate (用于 PostgreSQL), WeblogicDelegate (用于Weblogic提供的JDBC驱动), OracleDelegate (用于Oracle), 以及其他。

选定了你的委托之后,将它的类名配置给JDBCJobStore使用

1
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

接下来告知JobStore你使用的表名前缀

1
org.quartz.jobStore.tablePrefix = QRTZ_

最后你需要告知JobStore你要是用的数据源。命名的数据源必须也在Quartz配置文件里定义过了,在这个例子中,我们只写了个数据源的名字,但是对这个名字的定义也在配置文件里的某处。

1
org.quartz.jobStore.dataSource = myDS

如果你的调度器总是很忙(例如:总是有线程池线程数量个的作业在执行),那么此时你就应该考虑将线程池线程数+2,让它有余力保持对数据源的链接

org.quartz.jobStore.useProperties配置参数可以设置成true(默认是false)来告知JobStoreJobDataMap中的所有的值都是String类型,这样就能存成简单的名字-值对,而不是从反序列化来的更复杂的对象。当数据很长的时候,这样子也很安全,此外还避免了在序列化非字符串类的时候可能存在的版本问题。

TerracottaJobStore

TerracottaJobStore是Quartz 1.7新出的。它提供了不使用数据库但依然保持伸缩性和鲁棒性的手段。这意味着你可以将这些数据存储到应用的其他部分而不是放到数据库里。

TerracottaJobStore可以集群式运行也可以单独运行。它可以持久保存你的作业数据不管应用是不是发生了重启、崩溃等,因为数据存储在了Terracotta服务器上。它的性能比通过JDBCJobStore访问数据库好多了(好一个数量级),但也比RAMJobStore慢多了。

要使用TerracottaJobStore(假定你在使用StdSchedulerFactory),你只需要在配置文件中写明类型,然后给出Terracotta服务器的地址就好了

1
2
org.quartz.jobStore.class = org.terracotta.quartz.TerracottaJobStore
org.quartz.jobStore.tcConfigUrl = localhost:9510

关于JobStoreTerracotta的更多信息可以查看 Quartz Scheduler | Terracotta