`

quartz储存方式之JDBC JobStoreTX

 
阅读更多

这篇单单记录一下个人配置使用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: 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: false

org.quartz.jobStore.misfireThreshold: 60000

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.connectionProvider.class: org.quartz.examples.example17.MyPoolingconnectionProvider
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


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.MyPoolingconnectionProvider
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

它们的“键”必须是

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);
            } 

 

分享到:
评论

相关推荐

    spring整合quartz使用jdbc存储

    Quartz本身支持多种持久化策略,包括使用数据库(JDBC)来存储作业和触发器信息,这使得任务调度信息在系统重启后仍能保留。下面将详细介绍如何进行Spring与Quartz的整合,以及使用JDBC存储的相关步骤。 1. **...

    spring3+ quartz1.8使用以及eclipse代码

    Quartz支持多种集群策略,常见的包括基于数据库的Job存储和基于文件的Trigger存储。在`quartz.properties`中配置相应的集群参数,例如: ``` org.quartz.jobStore.isClustered=true org.quartz.jobStore....

    Quartz2.2.1存储与持久化-基于Spring的配置

    `jobStoreClass`指定了存储策略,这里是`JobStoreTX`,它是基于JDBC的事务型Job存储,适用于单机或集群环境。`tablePrefix`定义了在数据库中创建的Quartz表的前缀,避免与其他应用的表冲突。`clustered`属性表示是否...

    Quartzs -- JDBC-JobStore - Oracle 实现 + Cluster

    在 "Quartzs -- JDBC-JobStore - Oracle 实现 + Cluster" 的主题中,我们将探讨如何使用 Quartz 配合 JDBC 存储策略和 Oracle 数据库来实现分布式集群环境下的任务调度。 1. **JDBC-JobStore**: Quartz 提供了...

    quartz的持久化

    1. **JDBC 持久化**:这是 Quartz 最常见且推荐的持久化方式。Quartz 提供了一套 SQL 脚本,用户可以将其运行在支持的数据库上,创建所需的表结构。然后,Quartz 的 JobStore 实现(如 `org.quartz.impl....

    Quartz2.2.1java任务持久(mysql)存储demo以及资料

    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate # 配置数据源 org.quartz.dataSource.myDS....

    Spring3.2.3+Quartz2.2 整合配置

    需要注意的是,Quartz支持多种存储方式,如内存存储、文本文件存储以及JDBC存储(如上面示例)。选择合适的存储方式取决于任务数量、任务执行频率以及系统对高可用性和持久化的需求。同时,Quartz提供了丰富的API,...

    quartz2.1.6

    2. **配置文件**(如 `quartz.properties`):定义 Quartz 的行为,如数据库连接、线程池大小、作业存储方式等。 3. **应用中的 Job 类**:实现具体任务逻辑。 4. **Trigger 配置**:指定何时触发 Job。 在 Maven ...

    quartz在Spring中的配置

    &lt;prop key="org.quartz.jobStore.class"&gt;org.quartz.impl.jdbcjobstore.JobStoreTX &lt;prop key="org.quartz.jobStore.tablePrefix"&gt;QRTZ_ &lt;prop key="org.quartz.jobStore.useProperties"&gt;false &lt;prop key="org....

    SpringBoot集成Quartz分布式定时任务

    quartz.jobStore.type=org.quartz.impl.jdbcjobstore.JobStoreTX quartz.dataSource.quartzDataSource.driver-class-name=com.mysql.jdbc.Driver quartz.dataSource.quartzDataSource.url=jdbc:mysql://localhost...

    Quartz2.0持久化到数据库

    Quartz2.0支持多种持久化方式,包括JDBC(即数据库)、JDO、XML等。选择数据库持久化,尤其是像Oracle这样的企业级数据库,可以确保高可用性和数据的一致性。在Oracle数据库中,我们需要创建相应的表结构来存储...

    spring quartz集群配置

    &lt;property name="jobStoreClass" value="org.quartz.impl.jdbcjobstore.JobStoreTX"/&gt; &lt;property name="configLocation" value="classpath:quartz.properties"/&gt; ``` 在`quartz.properties`中,我们需要...

    quartz+spring分布式集群

    JDBC-JobStore是Quartz的一种存储策略,它利用数据库来存储作业和触发器的信息,使得在分布式环境中,多个Quartz实例能够共享相同的作业和触发器信息,实现任务的分布式调度。 以下是一些关键知识点: 1. **Quartz...

    Quartz集群配置和示例源码

    org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.dataSource=myDS # 数据源配置...

    quartz的jar包和配置文件

    org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix=QRTZ_ ``` 使用...

    quartz1.6.6 持久化实例

    - 配置文件(如`quartz.properties`)中需指定`org.quartz.jobStore.class`为JDBC JobStore的实现,如`org.quartz.impl.jdbcjobstore.JobStoreTX`。 - 同时,需要配置数据库连接信息,包括URL、用户名、密码等,...

    Quartz2.2-JobStore持久化到数据库

    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....

    spring集成quartz集群配置

    org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.dataSource=myDS org.quartz....

    quartz的jar包

    - **quartz.properties**:这是Quartz的主要配置文件,用于设置数据库连接、线程池大小、Job存储方式等。例如: ``` org.quartz.scheduler.instanceName = MyScheduler org.quartz.jobStore.class = org.quartz....

    web工程quartz的配置实例

    该文件中可以设置数据库连接、线程池大小、Job存储方式等。例如: ``` org.quartz.scheduler.instanceName = MyScheduler org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz....

Global site tag (gtag.js) - Google Analytics