调度器,负责具体读取触发器规则、调用任务、存取执行状态的组件。在之前的代码中,我们曾使用SchedulerFactory
创建Scheduler
,并在其中指定任务和触发器,并开启调度器。这里我们详细了解一下Scheduler
相关的操作。
Quartz框架中,Scheduler
由SchedulerFactory
创建,其中我们最常使用的就是默认的StdSchedulerFactory
,该工厂类会根据我们的配置文件quartz.properties
以及默认配置创建Scheduler
。
// 获取调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
启动调度器:
scheduler.start();
挂起(暂停)调度器:
scheduler.standby();
挂起后,可以再次调用scheduler.start()
方法恢复。
暂停调度器中一个任务:
scheduler.pauseJob(new JobKey("jobDetail", "demoGroup"));
恢复调度器中一个任务:
scheduler.resumeJob(new JobKey("jobDetail", "demoGroup"));
停止调度器:
scheduler.shutdown(true);
true
表示会等待所有任务执行完成后停止调度器,false
表示直接终止调度器Quartz支持通过JDBC方式保存调度信息,支持大多数主流数据库,之前在第一节中,我们配置过JDBCJobStore
将调度信息存储到数据库中,如果使用这种配置,我们创建的任务和触发器内容会写入数据库,即使应用程序关闭也不会删除,再次启动程序时直接从数据库中恢复即可。完整配置例子如下:
# 调度器实例名
org.quartz.scheduler.instanceName=QuartzScheduler
# 调度器实例ID 一般都为自动生成
org.quartz.scheduler.instanceId=AUTO
# 线程数
org.quartz.threadPool.threadCount=10
# 线程优先级 默认5即可
org.quartz.threadPool.threadPriority=5
# 线程池实现类
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
# 指定使用JDBCJobStore
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
# 开启集群模式
org.quartz.jobStore.isClustered=true
# 代理类用于指定数据库方言
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 数据源名
org.quartz.jobStore.dataSource=quartzDataSource
# 表前缀
org.quartz.jobStore.tablePrefix=QRTZ_
# 数据库驱动类
org.quartz.dataSource.quartzDataSource.driver=com.mysql.cj.jdbc.Driver
# 数据库链接
org.quartz.dataSource.quartzDataSource.URL=jdbc:mysql://127.0.0.1/demoquartz?useUnicode=true&characterEncoding=utf-8
# 数据库用户名
org.quartz.dataSource.quartzDataSource.user=root
# 数据库密码
org.quartz.dataSource.quartzDataSource.password=root
注意:将调度信息持久化到数据库后,我们每次启动程序就不需要重复创建任务、触发器了,StdSchedulerFactory.getDefaultScheduler()
创建调度器时,会自动从数据库中恢复调度数据,重复创建可能会报主键冲突的错误。
我们知道MySQL数据库在执行增删改时,会对数据行加排它锁,事务提交前其他线程无法对该行数据进行更新,Quartz的分布式锁就是使用这种基于数据库的排它锁来实现。
首先Quartz集群模式必须基于JDBCJobStore
实现,需要配置以下选项:
quartz.properties
# 开启集群模式
org.quartz.jobStore.isClustered=true
集群模式具有分布式锁,如果对于同一份数据库信息运行多个应用程序实例,只会有一个实例持有锁并执行任务,多实例下必须配置集群模式,否则数据可能遭到破坏。