quartz的数据库持久化,动态增删改操作(不重启服务器)

公司的定时任务越来越多,boss想把它们都放到一个服务器里管理,让我研究一下,弄一套方案出来。网上看了很多资料,相关的资料不多,读了源码,加上自己测试,总算弄出来,拿出来分享给大家。如果你想在服务器不重启的情况下,完成对定时任务的增删改操作,并且时时监测定时任务的状态,就耐心的读下去。

先看一下项目结构:

图片有点大,主要想给大家看的就是quartz.properties,我们就从这个配置文件开始说起。(记住,quartz.properties文件放在src目录下)

 

  1. quartz.properties

直接上代码:

 

#调度器属性

org.quartz.scheduler.instanceName:MyQuartzScheduler

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:20

org.quartz.threadPool.threadPriority:5

org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:true

#最长等待时间,跟任务的misfire有关

org.quartz.jobStore.misfireThreshold:60000

#存储属性

#org.quartz.jobStore.class:org.quartz.simpl.RAMJobStore

#持久化到数据库

org.quartz.jobStore.class= org.quartz.impl.jdbcjobstore.JobStoreTX

org.quartz.jobStore.driverDelegateClass== org.quartz.impl.jdbcjobstore.oracle.OracleDelegate

#表名前缀

org.quartz.jobStore.tablePrefix= QRTZ_

#数据源

org.quartz.jobStore.dataSource= myDS

#数据库信息

org.quartz.dataSource.myDS.driver= oracle.jdbc.driver.OracleDriver

org.quartz.dataSource.myDS.URL= jdbc:oracle:thin:@10.7.160.82:1521:cover

org.quartz.dataSource.myDS.user= cover_uat

org.quartz.dataSource.myDS.password= cover_uat123

org.quartz.dataSource.myDS.maxConnections= 25

这段代码大家在网上都能搜到详细的解释,如果想深入了解就去看看,如果只是想使用,看看下面我说的就可以了。

 

这里面特别要注意的几个字段

 

org.quartz.jobStore.class= org.quartz.impl.jdbcjobstore.JobStoreTX的意思是将定时任务持久化到数据库,如果是这样写org.quartz.jobStore.class:org.quartz.simpl.RAMJobStore就是将定时任务存在内存中。看到RAM三个字应该也理解一点了。持久化数据库有持久化数据库的好处,存在内存中也有优劣。但是要实现增删改还是要存在数据库中。需要改动的只有数据源和数据库配置信息。

 

2.持久化到数据库

既然选择了存到数据库中,当然要配置一下数据库的信息。表结构在你的quartz\quartz-2.1.7\docs\dbTables包里有脚本,这里我用的Oracle数据库,所以用的是Oracle数据库的脚本。数据源就是你配置weblogic的时候的jndi名称。按照你的数据库配置好以后。配置文件就搞定了,对于quartz的使用,我前面已经介绍过一个quartzManager方法,不知道的可以去quartz的使用查看。调用里面的添加方法,你可以在你的定时任务里打印一些信息到控制台。当定时任务执行后,去你的数据库看看,如果表QRTZ_CRON_TRIGGERS,QRTZ_JOB_DETAILS,QRTZ_TRIGGERS有相关信息的话,说明你已经成功将定时任务持久化到数据库中了。

 

3.动态添加定时任务

此时,添加定时任务就是让quartz可以从数据库中读到相关的数据,并且找到相关的类去执行。所以,我们先要准备相关的类,跟一开始一样,编辑好后,编辑成二进制文件,放在服务器的.class 文件下面,这样第一步就完成了,服务器已经能找到这个类了。然后就是怎么样让数据库多出这些数据,一开始我有想过,手动配这三张表。试了一下,不仅麻烦,而且还不能用。后来看了源码,才知道调度器好像自己维护了一张调度表。光数据库中有还是不管用的。为了解决问题,我往数据库里又加入了一张表。

create table QRTZ_JOB
(
  JOB_NAME       VARCHAR2(200) not null,
  JOB_GROUP      VARCHAR2(200) not null,
  DESCRIPTION    VARCHAR2(250),
  JOB_CLASS_NAME VARCHAR2(250) not null,
  CRON           VARCHAR2(120) not null
)

就是这样,我又开了一个定时任务,定时读取这张表,如果有数据,就根据数据启动定时任务,然后将表中数据删除。这样如果有新任务来就会被定时器读到,然后添加进去。

@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		// 查找数据库中是否有新增的任务
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		String sql = "select * from qrtz_job";
		String sql2 = "delete from qrtz_job";
		try {
			// 动态加载log4j2.xml文件
			LoggerContext logContext = (LoggerContext) LogManager.getContext(false);
			String path = AddNewJob.class.getResource("/log4j2.xml").getPath();
			File conFile = new File(path);
			logContext.setConfigLocation(conFile.toURI());
			logContext.reconfigure();

			conn = DBUtil.getConnection();
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();

			// 如果有,调用方法添加启动任务,将任务列表清空
			while (rs.next()) {
				System.out.println("添加新任务");
				System.out.println(rs.getString("JOB_NAME") + "-" + rs.getString("CRON") + "-" + rs.getString("JOB_CLASS_NAME"));
				QuartzManager.addJob(rs.getString("JOB_NAME"), rs.getString("JOB_GROUP"), rs.getString("JOB_NAME"), rs.getString("JOB_GROUP"), Class.forName(rs.getString("JOB_CLASS_NAME")),
						rs.getString("CRON"));
				log.info("添加新任务:" + rs.getString("JOB_NAME") + "-" + rs.getString("CRON") + "-" + rs.getString("JOB_CLASS_NAME"));
			}
			ps = conn.prepareStatement(sql2);
			ps.executeUpdate();
		} catch (Exception e) {
			log.error("动态添加新任务时出错:", e);
			e.printStackTrace();
		} finally {
			DBUtil.close(rs, ps, conn);
		}
	}

很简单的逻辑。到此为止,你的定时任务已经可以动态添加了。再不用为了一个定时任务重启服务器。

 

4.动态修改定时任务

定时修改定时任务就两步,1、改QRTZ_CRON_TRIGGERS表中的字段CRON_EXPRESSION。2、根据刚才的修改,修改表QRTZ_TRIGGERS的字段NEXT_FIRE_TIME。要求:下次执行时间-上次执行时间=CRON_EXPRESSION。多次修改,我发现要在定时任务未执行的时候修改,因为两个字段要同时修改才能生效。所以改一半的话任务一执行,另一个就还原了。所以改的时候找准定时任务两次执行的间隔修改。

 

5.动态删除定时任务

这个说不说大家应该都知道了,对,删除数据库关于这个定时任务的相关信息。读不到就不会执行了。

 

到这里,整个项目也算结束了,可是这时boss看完又提了一个需求,因为定时任务的错误很难定位,要求每一个定时任务都有一个属于自己的日志文件,这样谁的文件里有信息了,就表示谁发生了错误,再根据打印的错误修改即可。这里涉及到log4j的内容,我在另一个文章中说。文章链接:log4j动态加载

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值