一、为什么要持久化?
网上大多数的Quartz Demo都不是持久化的,都是存储在内存里面的。当程序突然被中断时,如断电,内存超出时,很有可能造成任务的丢失,为了解决这种情况,我们可以将调度信息存储到数据库里面,进行持久化,当程序被中断后,再次启动,仍然会保留中断之前的数据,继续执行,而并不是重新开始。
二、Quartz 两种存储类型
三、关于两种存储类型的配置
1、依赖文件
<!-- SpringBoot整合Quartz依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- jdbc_starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- druid_stater -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
2、 RAMJobStore
在application.yml文件中进行如下配置即可,启动项目后定时任务就可以正常运行。
3、JobStroeTX
1、创建SchedulerConfig文件
@Configuration
public class ScheduleConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
//quartz参数
Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "quartzScheduler");
prop.put("org.quartz.scheduler.instanceId", "AUTO");
//线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "20");
prop.put("org.quartz.threadPool.threadPriority", "5");
//JobStore 配置
// prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
//集群配置
prop.put("org.quartz.jobStore.isClustered", "false");
prop.put("org.quartz.jobStore.misfireThreshold", "12000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
factory.setQuartzProperties(prop);
factory.setSchedulerName("DemoScheduler");
//延时启动
factory.setStartupDelay(30);
factory.setApplicationContextSchedulerContextKey("applicationContextKey");
//可选 QuartzScheduler 启动更新已存在的Job
factory.setOverwriteExistingJobs(true);
//设置自动重启,默认为true
factory.setAutoStartup(true);
return factory;
}
@Bean(name = "scheduler")
public Scheduler scheduler(DataSource dataSource) throws SchedulerException {
return schedulerFactoryBean(dataSource).getScheduler();
}
}
2、在Service 层 注入 Scheduler即可。启动项目后定时任务就可以正常运行。
@Autowired
private Scheduler scheduler;
四、采用Qutarz持久化时遇到的坑
1、Caused by: org.quartz.SchedulerConfigException: DataSource name not set.
原因是 spring-boot-starter-parent 的版本问题导致的,spring-boot-starter-parent 版本不一样引用的 quartz的默认数据源的路径也发生了改变。
解决办法如下:
如果 spring-boot-starter-parent 的版本为 2.5.6 之后的版本 在 定时任务JDBC配置文件中应该修改如下操作
prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
如果 spring-boot-starter-parent 的版本为 2.5.6 之前的版本 在 定时任务JDBC配置文件中应该修改如下操作
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
2、Quartz调度程序作业未存储到数据库中
明明在项目中已经将 Quartz 数据库持久化配置完毕,每次添加定时任务时,任务添加成功且到达定时时间后,任务会被执行,但是任务却没有写入数据库。检查代码后,发现Scheduler注入的问题,因为项目中一直用的是默认的DefaultQuartzScheduler,也就意味着一直都是用的内存方式存储的数据,所以任务永远不会被写入数据库。
错误的写法:
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
正确的写法(在定时任务的配置文件中加入如下的写法即可):
@Bean(name = "scheduler")
public Scheduler scheduler(DataSource dataSource) throws SchedulerException {
return schedulerFactoryBean(dataSource).getScheduler();
}