Quartz持久化使用的一个错误

1、问题及解决

为了测试quartz任务调度是否好使,我在数据库表中添加了一个测试任务com.***.tasks.service.MyTask1。发现可以正常调度,然后我就讲数据中的配置给删除了,这是后再启动的时候就会报错,如下:

2018-08-23 16:49:24.430 [QuartzScheduler_schedulerFactoryBean-NON_CLUSTERED_MisfireHandler] ERROR org.quartz.impl.jdbcjobstore.JobStoreTX - MisfireHandler: Error handling misfires: Couldn't store trigger 'testTaskGrp.com.***.tasks.service.MyTask1' for 'testTaskGrp.com.***.tasks.service.MyTask1' job:com.***.tasks.service.MyTask1
org.quartz.JobPersistenceException: Couldn't store trigger 'testTaskGrp.com.***.tasks.service.MyTask1' for 'testTaskGrp.com.***.tasks.service.MyTask1' job:com.***.tasks.service.MyTask1
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1222)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.doUpdateOfMisfiredTrigger(JobStoreSupport.java:1036)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.recoverMisfiredJobs(JobStoreSupport.java:985)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.doRecoverMisfires(JobStoreSupport.java:3155)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$MisfireHandler.manage(JobStoreSupport.java:3913)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$MisfireHandler.run(JobStoreSupport.java:3934)
Caused by: java.lang.ClassNotFoundException: com.***.tasks.service.MyTask1
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper.loadClass(ResourceLoaderClassLoadHelper.java:76)
    at org.springframework.scheduling.quartz.ResourceLoaderClassLoadHelper.loadClass(ResourceLoaderClassLoadHelper.java:81)
    at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectJobDetail(StdJDBCDelegate.java:852)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1204)
    ... 5 common frames omitted

开始以为是代码缓存的事情,把本地缓存全部清除,发现依然不好使,然后想还是看看代码,发现如果任务不在使用的时候需要从Scheduler对象中删除,因为任务发布到它的数据表中了。然后从quartz任务表中删除所有与测试任务有关的信息就不再出现这个问题了。

2、quartz持久化实现

A、配置

#集群配置  
org.quartz.scheduler.skipUpdateCheck=true
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=true  
   
org.quartz.jobStore.misfireThreshold=60000
   
#============================================================================  
# Configure JobStore  
#============================================================================  
   
#默认配置,数据保存到内存  
#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.misfireThreshold=60000
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.dataSource=quartzDataSource
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=15000

org.quartz.dataSource.quartzDataSource.driver=oracle.jdbc.OracleDriver
org.quartz.dataSource.quartzDataSource.URL=jdbc:oracle:thin:@//localhost:1521/orcl
org.quartz.dataSource.quartzDataSource.user=***
org.quartz.dataSource.quartzDataSource.password=***
org.quartz.dataSource.quartzDataSource.maxConnections=10

B、任务加载及启动

@Autowired
	private Scheduler scheduler;
	
	@Autowired
	private Qrtz***JobsMapper qrtz***JobsMapper;
	
	@PostConstruct
	@SuppressWarnings("unchecked")
	public void execute() throws Exception{
		List<Qrtz***Jobs> allJobs = qrtz***JobsMapper.queryQrtz***JobsByAll();
		for(Qrtz***Jobs scheduleJob : allJobs){
			TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobname(), scheduleJob.getJobgroup());  
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); 
            if (null == trigger) { 
            	if(scheduleJob.getStatus() == 0){
            		log.info("任务{}.{}状态为禁止,不启动!", scheduleJob.getJobgroup(), scheduleJob.getJobname());
            		continue;
            	}
            	log.info("任务{}.{}启动。", scheduleJob.getJobgroup(), scheduleJob.getJobname());
            	JobDetail jobDetail=null;  
                //创建JobDetail(数据库中job_name存的任务全路径,这里就可以动态的把任务注入到JobDetail中)  
                jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(scheduleJob.getJobname())).withIdentity(scheduleJob.getJobname(), scheduleJob.getJobgroup()).build();  
                //表达式调度构建器  
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCron());  
                //按新的cronExpression表达式构建一个新的trigger  
                trigger = TriggerBuilder.newTrigger().withIdentity(scheduleJob.getJobname(), scheduleJob.getJobgroup()).withSchedule(scheduleBuilder).build();  
                //把trigger和jobDetail注入到调度器  
                scheduler.scheduleJob(jobDetail, trigger);  
            }else{
            	if(scheduleJob.getStatus() == 0){
            		// 当前任务状态为禁止
            		log.info("任务{}.{}状态为禁止,移除任务。", scheduleJob.getJobgroup(), scheduleJob.getJobname());
            		JobKey jobKey = JobKey.jobKey(scheduleJob.getJobname(), scheduleJob.getJobgroup());  
                    scheduler.deleteJob(jobKey);  
                    continue; 
            	}else{
            		String searchCron = scheduleJob.getCron(); //获取数据库的  
                    String currentCron = trigger.getCronExpression();  
                    if(!searchCron.equals(currentCron)){
                    	log.info("任务{}.{}变化,启动。", scheduleJob.getJobgroup(), scheduleJob.getJobname());
                    	//说明该任务有变化,需要更新quartz中的对应的记录 
                    	CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(searchCron);  
                        //按新的cronExpression表达式重新构建trigger  
                        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();  
                        //按新的trigger重新设置job执行  
                        scheduler.rescheduleJob(triggerKey, trigger); 
                    }else{
                    	log.info("任务{}.{}无变化,正常启动。", scheduleJob.getJobgroup(), scheduleJob.getJobname());
                    }
            	}
            }
		}
	}

C、编写任务

@Component
@DisallowConcurrentExecution
public class TestJob implements Job {
	
	private Logger log = LoggerFactory.getLogger(TestJob.class);

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		CronTrigger trigger = (CronTrigger) context.getTrigger();  
        String corn = trigger.getCronExpression();  
        String jobName = trigger.getKey().getName();  
        String jobGroup = trigger.getKey().getGroup();  
        log.info("任务表达式:{},任务名称:{},任务组:{}", corn, jobName, jobGroup);
	}

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值