博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
quartz储存方式之JDBC JobStoreTX和JNDI JobStoreCMT
阅读量:7190 次
发布时间:2019-06-29

本文共 13053 字,大约阅读时间需要 43 分钟。

hot3.png

这篇单单记录一下个人配置使用quartz的JDBC JobStoreTX的过程以及其中遇到的问题,这里的quartz是version2.2.1,数据库使用的mysql。

JDBCJobStore储存是速度比较慢的,但是也不至于很坏,通过JDBCJobStore储存于数据库的方式适用于Oracle,PostgreSQL, MySQL, MS SQLServer, HSQLDB, DB2等数据库。

1) 建表

在下载的文件的docs/dbTables目录下有对应建表语句,如果没有对应于应用的就自己改动来适应。这些个表都有"QRTZ"前缀,可以作为区别于别的命名。

2) 选定事务

如果你不需要绑定其他事务处理,你可以选择quartz的事务,其通过JobStoreTX来管理,这也是常用的选择,当然如果你要和你的应用容器一起管理,那你可以使用quartz的

JobStoreCMT,quartz通过JobStoreCMT来的使用来让你的应用容器管理quartz的事务。

3) 创建数据源

一个是提供一个connection,让quartz可以连接到数据库,另一个是提供的JNDI的方式,让quartz可以从所在容器中获取到。

使用JDBC连接方式(假设你使用的是StdSchedulerFactory):

首先:

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
或者
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT

这里当然选择JobStoreTX。

其次:
选定JDBC代理类,quartz里提供了StdJDBCDelegate,如果这个不能正常工作的,你可以选用其他代理类(在org.quar.impl.jdbcjobstore package或者其子包中可以找到),包括DB2v6Delegate (for DB2 version 6 and earlier), HSQLDBDelegate (for HSQLDB),MSSQLDelegate (for Microsoft SQLServer), PostgreSQLDelegate (for PostgreSQL),
WeblogicDelegate (for using JDBC drivers made by WebLogic), OracleDelegate (for using Oracle)等等。
并这样配置:
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
第三:
指定前缀
org.quartz.jobStore.tablePrefix = QRTZ_
第四:
指定数据源名称:
org.quartz.jobStore.dataSource = myDS
第五:定义ConnectionProvider的实现类

这里我找了一下,quartz提供了一个org.quartz.utils.PoolingConnectionProvider,于是,我就有了如下配置:

org.quartz.dataSource.myDS.connectionProvider.class:org.quartz.utils.PoolingConnectionProvider

第六:配置数据源属性

org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver

org.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8
org.quartz.dataSource.myDS.user: root
org.quartz.dataSource.myDS.password: root
org.quartz.dataSource.myDS.maxConnections = 30

完事,使用最简单的一个例子来跑跑,可是报错了……

Caused by: java.lang.InstantiationException: org.quartz.utils.PoolingConnectionProvider

at java.lang.Class.newInstance(Unknown Source)
at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:936)
... 3 more

跟了一下源码得到详细一点的原因:

                ConnectionProvider cp = null;

                try {
                    cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance();
                } catch (Exception e) {
                    initException = new SchedulerException("ConnectionProvider class '" + cpClass
                            + "' could not be instantiated.", e);
                    throw initException;
                }

红色那行报的:

org.eclipse.debug.core.DebugException: com.sun.jdi.ClassNotLoadedException: Type has not been loaded occurred while retrieving component type of array.

百度了一把,没什么收获,看看文档,只说定义自己的这个类,但是为啥,也没有代码,为什么不告诉直接用上述的那个provider呢?

直接测试一下loadclass("org.quartz.utils.PoolingConnectionProvider");是没有问题的,那就是newInstance();的时候有问题咯。靠谱的还是JDK文档,立马去看一下,果然有收获:创建此Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。 

如同空参数……

肯定是那个provider没有提供无参构造……再去看看呢,果然没有,好吧,我承认我懒了那么一丢丢。

那我再找找有没有其他的用于设置这个的吧,居然没有找到(估计没有找仔细),还是得定义一个自己的provider,没事,就参考这个provider,还是用C3P0来定义呗。

定义好后,来试试,果然顶用。以下是我的可运行代码:

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: DefaultQuartzSchedulerorg.quartz.scheduler.rmi.export: falseorg.quartz.scheduler.rmi.proxy: falseorg.quartz.scheduler.wrapJobExecutionInUserTransaction: falseorg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPoolorg.quartz.threadPool.threadCount: 10org.quartz.threadPool.threadPriority: 5org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: falseorg.quartz.jobStore.misfireThreshold: 60000org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegateorg.quartz.jobStore.tablePrefix: QRTZ_org.quartz.jobStore.dataSource: myDSorg.quartz.dataSource.myDS.connectionProvider.class: org.quartz.examples.example17.MyPoolingconnectionProviderorg.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driverorg.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8org.quartz.dataSource.myDS.user: rootorg.quartz.dataSource.myDS.password: rootorg.quartz.dataSource.myDS.maxConnections: 30

MyPoolingconnectionProvider.java

package org.quartz.examples.example17;import java.beans.PropertyVetoException;import java.sql.Connection;import java.sql.SQLException;import org.quartz.SchedulerException;import org.quartz.utils.ConnectionProvider;import com.mchange.v2.c3p0.ComboPooledDataSource;/** *  * @author wz * */public class MyPoolingconnectionProvider implements ConnectionProvider { /** Default maximum number of database connections in the pool. */ public static final int DEFAULT_DB_MAX_CONNECTIONS = 10; /** Default maximum number of database connections in the pool. */ public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120; private String driver; private String url; private String user; private String password; private int maxConnections; private int maxCachedStatementsPerConnection; private int maxIdleSeconds; private String validationQuery; private int idleConnectionValidationSeconds; private boolean validateOnCheckout; private String discardIdleConnectionsSeconds; private ComboPooledDataSource datasource; /**  * 无参构造,必须要有[没有其他构造的话也可以不写]  */ public MyPoolingconnectionProvider() { } public Connection getConnection() throws SQLException {  return datasource.getConnection(); } public void shutdown() throws SQLException {  datasource.close(); } /**  * 初始化方法,应该在调用其setter后调用  */ public void initialize() throws SQLException {  if (this.url == null) {   throw new SQLException("DBPool could not be created: DB URL cannot be null");  }  if (this.driver == null) {   throw new SQLException("DBPool driver could not be created: DB driver class name cannot be null!");  }  if (this.maxConnections < 0) {   throw new SQLException("DBPool maxConnectins could not be created: Max connections must be greater than zero!");  }  datasource = new ComboPooledDataSource();  try {   datasource.setDriverClass(this.driver);  } catch (PropertyVetoException e) {   try {    throw new SchedulerException("Problem setting driver class name on datasource: " + e.getMessage(), e);   } catch (SchedulerException e1) {   }  }  datasource.setJdbcUrl(this.url);  datasource.setUser(this.user);  datasource.setPassword(this.password);  datasource.setMaxPoolSize(this.maxConnections);  datasource.setMinPoolSize(1);  datasource.setMaxIdleTime(maxIdleSeconds);  datasource.setMaxStatementsPerConnection(this.maxCachedStatementsPerConnection);  if (this.validationQuery != null) {   datasource.setPreferredTestQuery(this.validationQuery);   if (!validateOnCheckout)    datasource.setTestConnectionOnCheckin(true);   else    datasource.setTestConnectionOnCheckout(true);   datasource.setIdleConnectionTestPeriod(this.idleConnectionValidationSeconds);  } } /*-------------------------------------------------  *   * setters 如果有必要,你可以添加一些getter  * ------------------------------------------------  */ public void setDriver(String driver) {  this.driver = driver; } public void setUrl(String url) {  this.url = url; } public void setUser(String user) {  this.user = user; } public void setPassword(String password) {  this.password = password; } public void setMaxConnections(int maxConnections) {  this.maxConnections = maxConnections; } public void setMaxCachedStatementsPerConnection(int maxCachedStatementsPerConnection) {  this.maxCachedStatementsPerConnection = maxCachedStatementsPerConnection; } public void setMaxIdleSeconds(int maxIdleSeconds) {  this.maxIdleSeconds = maxIdleSeconds; } public void setValidationQuery(String validationQuery) {  this.validationQuery = validationQuery; } public void setIdleConnectionValidationSeconds(int idleConnectionValidationSeconds) {  this.idleConnectionValidationSeconds = idleConnectionValidationSeconds; } public void setValidateOnCheckout(boolean validateOnCheckout) {  this.validateOnCheckout = validateOnCheckout; } public void setDiscardIdleConnectionsSeconds(String discardIdleConnectionsSeconds) {  this.discardIdleConnectionsSeconds = discardIdleConnectionsSeconds; } public void setDatasource(ComboPooledDataSource datasource) {  this.datasource = datasource; } protected ComboPooledDataSource getDataSource() {  return datasource; }}

SimpleExample.java

package org.quartz.examples.example17;import java.util.Date;import org.quartz.DateBuilder;import org.quartz.JobBuilder;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.quartz.SchedulerFactory;import org.quartz.TriggerBuilder;import org.quartz.impl.StdSchedulerFactory;import org.quartz.impl.triggers.SimpleTriggerImpl;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class SimpleExample{  public void run()    throws Exception  {    Logger log = LoggerFactory.getLogger(SimpleExample.class);    log.info("------- Initializing ----------------------");    //通过调度器工厂获取调度器,初始化工程时须指定其使用我们自己的配置文件    SchedulerFactory sf = new StdSchedulerFactory("org/quartz/examples/example17/quartz.properties");    Scheduler sched = sf.getScheduler();        //这儿clear一下,因为使用数据库储存方式时,shutdown的时候没有清除,第二次运行会报Job is already exist    sched.clear();     log.info("------- Initialization Complete -----------");    Date runTime = DateBuilder.evenMinuteDate(new Date());    log.info("------- Scheduling Job  -------------------");        //创建任务详情    JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();    //创建触发器    SimpleTriggerImpl trigger = (SimpleTriggerImpl)TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startAt(new Date()).build();    trigger.setRepeatCount(5);    trigger.setRepeatInterval(3000);    log.info("------- Starttime =  "+trigger.getStartTime()+" -----------------");        //调度器、触发器、任务,三者关联    sched.scheduleJob(job, trigger);    log.info(job.getKey() + " will run at: " + runTime);    //调度启动    sched.start();    log.info("------- Started Scheduler -----------------");    log.info("------- Waiting 1 minute... -------------");    try    {      Thread.sleep(60000L);    }    catch (Exception e)    {    }    log.info("------- Shutting Down ---------------------");    //调度关闭    sched.shutdown(true);    log.info("------- Shutdown Complete -----------------");  }  public static void main(String[] args) throws Exception  {    SimpleExample example = new SimpleExample();    example.run();  }}

当然,运行example之前,得先添加mysql的driver的包,然后在mysql里建立一个叫“quartz”的database,并将docs/dbTables下的tables_mysql.sql脚本运行一下以建表。

注意:

1) org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX,这个配置在这儿当然是用这个,

而org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate则根据你的数据,通常使用当前这个,如果这个不适用就去quartz里org.quar.impl.jdbcjobstore包或其子包下找找,如还是未能满足需求,就自己实现一个。

2) org.quartz.jobStore.tablePrefix: QRTZ_,这个是quartz默认的,tables_mysql.sql以及一些其他操作(比如clear等)的代码都这样写了,所以就不要去修改了。

3) org.quartz.jobStore.dataSource: myDS这个的“键”必须是org.quartz.jobStore.dataSource,而“值”随你取,但必须有。

4) dataSource的属性配置,如下几个(可以自己添加其他的对应修改provider)

org.quartz.dataSource.myDS.connectionProvider.class: org.quartz.examples.example17.MyPoolingconnectionProviderorg.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driverorg.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8org.quartz.dataSource.myDS.user: rootorg.quartz.dataSource.myDS.password: rootorg.quartz.dataSource.myDS.maxConnections: 30

 

它们的“键”必须是

org.quartz.dataSource."+yourdatasourcename+"."+yourProvider#datamembername

原因如下:

String[] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX);        for (int i = 0; i < dsNames.length; i++) {            PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup(                    PROP_DATASOURCE_PREFIX + "." + dsNames[i], true));            String cpClass = pp.getStringProperty(PROP_CONNECTION_PROVIDER_CLASS, null);            // custom connectionProvider...            if(cpClass != null) {                ConnectionProvider cp = null;                try {                    cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance();                } catch (Exception e) {                    initException = new SchedulerException("ConnectionProvider class '" + cpClass                            + "' could not be instantiated.", e);                    throw initException;                }                try {                    // remove the class name, so it isn't attempted to be set                    pp.getUnderlyingProperties().remove(                            PROP_CONNECTION_PROVIDER_CLASS);                    setBeanProps(cp, pp.getUnderlyingProperties());                    cp.initialize();                } catch (Exception e) {                    initException = new SchedulerException("ConnectionProvider class '" + cpClass                            + "' props could not be configured.", e);                    throw initException;                }                dbMgr = DBConnectionManager.getInstance();                dbMgr.addConnectionProvider(dsNames[i], cp);            }

转载于:https://my.oschina.net/javayan/blog/605904

你可能感兴趣的文章
ThinkPHP框架视图详细介绍 View 视图--模板(九)
查看>>
BZOJ4123 : [Baltic2015]Hacker
查看>>
蓝牙介绍
查看>>
BZOJ1110 : [POI2007]砝码Odw
查看>>
也谈C#之Json,从Json字符串到类代码
查看>>
javascript事件流机制
查看>>
谈话Java在ThreadLocal理解类
查看>>
随笔2
查看>>
ListView嵌套GridView显示不完整的解决方案
查看>>
创建文件/目录
查看>>
TPS和事务响应时间的关系
查看>>
throw new OAException执行了,却没有正常抛出异常!
查看>>
BZOJ3456 : 城市规划
查看>>
图片懒加载
查看>>
Appium入门示例(Java)
查看>>
Android Studio导入GitHub上的项目常见问题(以图片轮播开源项目为实例)
查看>>
【<td>】使<td>标签内容居上
查看>>
出现The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path错误
查看>>
Serial Wire Debug (SWD) Interface -- PSoc5
查看>>
jenkins综合cobertura,来电显示cobertura的report
查看>>