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

[plain] view plain copy

  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. org.quartz.scheduler.instanceName: DefaultQuartzScheduler
  6. org.quartz.scheduler.rmi.export: false
  7. org.quartz.scheduler.rmi.proxy: false
  8. org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
  9. org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
  10. org.quartz.threadPool.threadCount: 10
  11. org.quartz.threadPool.threadPriority: 5
  12. org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: false
  13. org.quartz.jobStore.misfireThreshold: 60000
  14. org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
  15. org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
  16. org.quartz.jobStore.tablePrefix: QRTZ_
  17. org.quartz.jobStore.dataSource: myDS
  18. org.quartz.dataSource.myDS.connectionProvider.class: org.quartz.examples.example17.MyPoolingconnectionProvider
  19. org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver
  20. org.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8
  21. org.quartz.dataSource.myDS.user: root
  22. org.quartz.dataSource.myDS.password: root
  23. org.quartz.dataSource.myDS.maxConnections: 30

MyPoolingconnectionProvider.java

[java] view plain copy

  1. package org.quartz.examples.example17;
  2. import java.beans.PropertyVetoException;
  3. import java.sql.Connection;
  4. import java.sql.SQLException;
  5. import org.quartz.SchedulerException;
  6. import org.quartz.utils.ConnectionProvider;
  7. import com.mchange.v2.c3p0.ComboPooledDataSource;
  8. /**
  9. *
  10. * @author wz
  11. *
  12. */
  13. public class MyPoolingconnectionProvider implements ConnectionProvider {
  14. /** Default maximum number of database connections in the pool. */
  15. public static final int DEFAULT_DB_MAX_CONNECTIONS = 10;
  16. /** Default maximum number of database connections in the pool. */
  17. public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120;
  18. private String driver;
  19. private String url;
  20. private String user;
  21. private String password;
  22. private int maxConnections;
  23. private int maxCachedStatementsPerConnection;
  24. private int maxIdleSeconds;
  25. private String validationQuery;
  26. private int idleConnectionValidationSeconds;
  27. private boolean validateOnCheckout;
  28. private String discardIdleConnectionsSeconds;
  29. private ComboPooledDataSource datasource;
  30. /**
  31. * 无参构造,必须要有[没有其他构造的话也可以不写]
  32. */
  33. public MyPoolingconnectionProvider() {
  34. }
  35. public Connection getConnection() throws SQLException {
  36. return datasource.getConnection();
  37. }
  38. public void shutdown() throws SQLException {
  39. datasource.close();
  40. }
  41. /**
  42. * 初始化方法,应该在调用其setter后调用
  43. */
  44. public void initialize() throws SQLException {
  45. if (this.url == null) {
  46. throw new SQLException("DBPool could not be created: DB URL cannot be null");
  47. }
  48. if (this.driver == null) {
  49. throw new SQLException("DBPool driver could not be created: DB driver class name cannot be null!");
  50. }
  51. if (this.maxConnections < 0) {
  52. throw new SQLException("DBPool maxConnectins could not be created: Max connections must be greater than zero!");
  53. }
  54. datasource = new ComboPooledDataSource();
  55. try {
  56. datasource.setDriverClass(this.driver);
  57. } catch (PropertyVetoException e) {
  58. try {
  59. throw new SchedulerException("Problem setting driver class name on datasource: " + e.getMessage(), e);
  60. } catch (SchedulerException e1) {
  61. }
  62. }
  63. datasource.setJdbcUrl(this.url);
  64. datasource.setUser(this.user);
  65. datasource.setPassword(this.password);
  66. datasource.setMaxPoolSize(this.maxConnections);
  67. datasource.setMinPoolSize(1);
  68. datasource.setMaxIdleTime(maxIdleSeconds);
  69. datasource.setMaxStatementsPerConnection(this.maxCachedStatementsPerConnection);
  70. if (this.validationQuery != null) {
  71. datasource.setPreferredTestQuery(this.validationQuery);
  72. if (!validateOnCheckout)
  73. datasource.setTestConnectionOnCheckin(true);
  74. else
  75. datasource.setTestConnectionOnCheckout(true);
  76. datasource.setIdleConnectionTestPeriod(this.idleConnectionValidationSeconds);
  77. }
  78. }
  79. /*-------------------------------------------------
  80. *
  81. * setters 如果有必要,你可以添加一些getter
  82. * ------------------------------------------------
  83. */
  84. public void setDriver(String driver) {
  85. this.driver = driver;
  86. }
  87. public void setUrl(String url) {
  88. this.url = url;
  89. }
  90. public void setUser(String user) {
  91. this.user = user;
  92. }
  93. public void setPassword(String password) {
  94. this.password = password;
  95. }
  96. public void setMaxConnections(int maxConnections) {
  97. this.maxConnections = maxConnections;
  98. }
  99. public void setMaxCachedStatementsPerConnection(int maxCachedStatementsPerConnection) {
  100. this.maxCachedStatementsPerConnection = maxCachedStatementsPerConnection;
  101. }
  102. public void setMaxIdleSeconds(int maxIdleSeconds) {
  103. this.maxIdleSeconds = maxIdleSeconds;
  104. }
  105. public void setValidationQuery(String validationQuery) {
  106. this.validationQuery = validationQuery;
  107. }
  108. public void setIdleConnectionValidationSeconds(int idleConnectionValidationSeconds) {
  109. this.idleConnectionValidationSeconds = idleConnectionValidationSeconds;
  110. }
  111. public void setValidateOnCheckout(boolean validateOnCheckout) {
  112. this.validateOnCheckout = validateOnCheckout;
  113. }
  114. public void setDiscardIdleConnectionsSeconds(String discardIdleConnectionsSeconds) {
  115. this.discardIdleConnectionsSeconds = discardIdleConnectionsSeconds;
  116. }
  117. public void setDatasource(ComboPooledDataSource datasource) {
  118. this.datasource = datasource;
  119. }
  120. protected ComboPooledDataSource getDataSource() {
  121. return datasource;
  122. }
  123. }

SimpleExample.java

[java] view plain copy

  1. package org.quartz.examples.example17;
  2. import java.util.Date;
  3. import org.quartz.DateBuilder;
  4. import org.quartz.JobBuilder;
  5. import org.quartz.JobDetail;
  6. import org.quartz.Scheduler;
  7. import org.quartz.SchedulerFactory;
  8. import org.quartz.TriggerBuilder;
  9. import org.quartz.impl.StdSchedulerFactory;
  10. import org.quartz.impl.triggers.SimpleTriggerImpl;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. public class SimpleExample
  14. {
  15. public void run()
  16. throws Exception
  17. {
  18. Logger log = LoggerFactory.getLogger(SimpleExample.class);
  19. log.info("------- Initializing ----------------------");
  20. //通过调度器工厂获取调度器,初始化工程时须指定其使用我们自己的配置文件
  21. SchedulerFactory sf = new StdSchedulerFactory("org/quartz/examples/example17/quartz.properties");
  22. Scheduler sched = sf.getScheduler();
  23. //这儿clear一下,因为使用数据库储存方式时,shutdown的时候没有清除,第二次运行会报Job is already exist
  24. sched.clear();
  25. log.info("------- Initialization Complete -----------");
  26. Date runTime = DateBuilder.evenMinuteDate(new Date());
  27. log.info("------- Scheduling Job  -------------------");
  28. //创建任务详情
  29. JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
  30. //创建触发器
  31. SimpleTriggerImpl trigger = (SimpleTriggerImpl)TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startAt(new Date()).build();
  32. trigger.setRepeatCount(5);
  33. trigger.setRepeatInterval(3000);
  34. log.info("------- Starttime =  "+trigger.getStartTime()+" -----------------");
  35. //调度器、触发器、任务,三者关联
  36. sched.scheduleJob(job, trigger);
  37. log.info(job.getKey() + " will run at: " + runTime);
  38. //调度启动
  39. sched.start();
  40. log.info("------- Started Scheduler -----------------");
  41. log.info("------- Waiting 1 minute... -------------");
  42. try
  43. {
  44. Thread.sleep(60000L);
  45. }
  46. catch (Exception e)
  47. {
  48. }
  49. log.info("------- Shutting Down ---------------------");
  50. //调度关闭
  51. sched.shutdown(true);
  52. log.info("------- Shutdown Complete -----------------");
  53. }
  54. public static void main(String[] args) throws Exception
  55. {
  56. SimpleExample example = new SimpleExample();
  57. example.run();
  58. }
  59. }

当然,运行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):

[html] view plain copy

  1. org.quartz.dataSource.myDS.connectionProvider.class: org.quartz.examples.example17.MyPoolingconnectionProvider
  2. org.quartz.dataSource.myDS.driver: com.mysql.jdbc.Driver
  3. org.quartz.dataSource.myDS.url: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf-8
  4. org.quartz.dataSource.myDS.user: root
  5. org.quartz.dataSource.myDS.password: root
  6. org.quartz.dataSource.myDS.maxConnections: 30

它们的“键”必须是

[html] view plain copy

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

原因如下:

[java] view plain copy

    1. String[] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX);
    2. for (int i = 0; i < dsNames.length; i++) {
    3. PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup(
    4. PROP_DATASOURCE_PREFIX + "." + dsNames[i], true));
    5. String cpClass = pp.getStringProperty(PROP_CONNECTION_PROVIDER_CLASS, null);
    6. // custom connectionProvider...
    7. if(cpClass != null) {
    8. ConnectionProvider cp = null;
    9. try {
    10. cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance();
    11. } catch (Exception e) {
    12. initException = new SchedulerException("ConnectionProvider class ‘" + cpClass
    13. + "‘ could not be instantiated.", e);
    14. throw initException;
    15. }
    16. try {
    17. // remove the class name, so it isn‘t attempted to be set
    18. pp.getUnderlyingProperties().remove(
    19. PROP_CONNECTION_PROVIDER_CLASS);
    20. setBeanProps(cp, pp.getUnderlyingProperties());
    21. cp.initialize();
    22. } catch (Exception e) {
    23. initException = new SchedulerException("ConnectionProvider class ‘" + cpClass
    24. + "‘ props could not be configured.", e);
    25. throw initException;
    26. }
    27. dbMgr = DBConnectionManager.getInstance();
    28. dbMgr.addConnectionProvider(dsNames[i], cp);
    29. }
时间: 2024-11-10 14:08:25

quartz储存方式之JDBC JobStoreTX的相关文章

关系型数据库与HBase的数据储存方式区别

如今Bigtable型(列族)数据库应用越来越广,功能也很强大.但是很多人还是把它当做关系型数据库在使用,用原来关系型数据库的思维建表.存储.查询.本文以hbase举例讲述数据模式的变化. 传统关系型数据库(mysql,oracle)数据存储方式主要如下: 图一 上图是个很典型的数据储存方式,我把每条记录分成3部分:主键.记录属性.索引字段.我们会对索引字段建立索引,达到二级索引的效果. 但是随着业务的发展,查询条件越来越复杂,需要更多的索引字段,且很多值都不存在,如下图: 图二 上图是6个索

浏览器本地储存方式有哪些?cookie、localStorage、sessionStorage

现阶段,浏览器提供的储存方式常用的有三种,cookie.localStorage.sessionStorage 1.cookie 概念:cookie 是浏览器中用于保存少量信息的一个对象 基本特征: 1)以域名为单位的,每个网站的cookie都保存在此网站的域名下,当下一次访问该网站的时候,就可以通过cookie访问保存的消息 2)每个浏览器保存cookie的位置不同,都保存在浏览器内部,可以通过相应的操作查看 3)每个浏览器保存cookie的数量限制不同,一般每个网站下不大于50个,不大于4k

wemall app商城源码Android数据的SharedPreferences储存方式

wemall-mobile是基于WeMall的Android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.本文分享wemall app商城源码Android数据的SharedPreferences储存方式,供技术员参考学习.        SharedPreferences:除了SQLite数据库外,SharedPreferences也是一种轻型的数据储存方式,它的本质是基于XML文件存储key-value键值对数据,通常用来储存一些简单的配置信息.Sha

Android下的数据储存方式(三)

  Android下最好的数据储存方式:关系型数据库sqlite.   数据库的创建:使用SqliteOpenHelper类 结合SqliteOpenHelper类和SQLiteDatabase类的帮助,我们可以方便地对数据库进行CURD操作.   数据库的创建: 我们主要通过在SqliteOpenHelper类的onCreate方法中创建数据库表. 那么,onCreate方法又是在什么时候执行的呢? 我们先写一下代码: package com.whathecode.db; import and

Android下的数据储存方式( 二)

  在上一篇文章中我们介绍了SharedPreferences的使用方法. 今天我们继续介绍另一种储存数据的方式:使用内部储存和外部储存   每一个Android设备都拥有两个数据储存区域:外部储存和外部储存 那么我们应该采用哪种储存方式呢? 我们先对比一下这两种储存方式的不同: 内部储存: 总是可用的 保存在这里的文件只能被你的app访问 当程序被卸载的时候,系统会删除所有属于该应用的文件 当你不希望你的文件被其他人或应用访问到的时候,内部储存是最好的选择 外部储存: 当sd卡被用户卸载的时候

Python与C储存方式的区别

在Alex视频课程中得知Python中: a=2 b=a a=3 该过程中的内存储存方式为: 1.先再内存中开栈存储2这个数据的空间 2.a指向数据为2的内存空间地址 3.b=a 此时b指向2的内存空间的地址 4.a=3 内存中开栈存储3这个数据的空间 5.此时a=3中,a重新指向数据为3的内存地址 总结:Python是动态语言,变量只是对象的引用 并在VC中作简单的测试 int i=1; int y=i; i=2; 在调试过程中得知 int i=1;            mov     dw

PHP中的Session储存方式优化

1:查看当前PHP版本中Seesion支持的储存方式   可以看出当前Session支持的储存方式有以下几种 files:文件模式,PHP默认的储存方式,把储存的值放在服务器的指定目录里 user:用户模式,暂时不了解 redis:支持redis储存.通过上面的图,可以看出当前session是redis储存,并指定了连接信息 memcache:支持memcache储存 2:redis|memcache储存的配置方式(支持redis|memcache拓展) 一:php.ini配置(推荐) sess

动态储存方式和静态储存方式

变量从存在的时间(生存期)角度来分,可以分为动态储存方式和静态储存方式. 所谓静态存储方式是指在程序运行开始时由系统分配固定的储存空间的方式. 动态储存方式则是在程序运行期间根据需要进行动态的分配储存空间的方式. 存储空间分为3部分:(1)程序区(2)静态存储区(3)动态存储区. 在C语言中,每一个变量和函数都有两个属性:数据类型和数据的存储类别. 对数据型(如整型,字符型等):储存类别指的是数据在内存中的储存方式.具体包含四种:自动的(auto),静态的(static),寄存器的(regist

图的3种储存方式

图的储存方式有三种 一.邻接矩阵 优点:简洁明了,调用方便,简单易写: 缺点:内存占用大,而且没办法存重边(可能可以,但我不会),点的个数超过 3000 直接爆炸 适用范围:点的个数少,稠密图,一般结合floyed使用,可以传递闭包. 代码: scanf("%d%d",&u,&v,&w); a[u][v]=w; a[v][u]=w;// 双向边 二.邻接表 优点:占用空间小,可以快速查找每个点的出度,重边可以存,写着较为方便 缺点:查找和删除边很不方便,对于无向