Quartzsql如何新建触发器job 和 触发器的问题

博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Quartz 2.2 的实现原理和运行过程
一、Quartz 的几个概念类
这几个概念类,是我们调用Quartz任务调度的基础。了解清楚之后,我们再来看一下如何去启动和关闭一个Quartz调度程序。
1、org.quartz.Job
它是一个抽象接口,表示一个工作,也就是我们要执行的具体内容,他只定义了一个几口方法:
void execute(JobExecutionContext context)
作用等同Spring的:
org.springframework.scheduling.quartz.QuartzJobBean 2、org.quartz.JobDetail
JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,它包含了这个任务调度的方案和策略。
他的实现类:
org.quartz.impl.JobDetailImpl
作用等同Spring:
org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean 3、org.quartz.Trigger
它是一个抽象接口,表示一个调度参数的配置,通过配置它,来告诉调度容器什么时候去调用JobDetail。
他的两个实现类:
org.quartz.impl.triggers.SimpleTriggerImpl
org.quartz.impl.triggers.CronTriggerImpl
等同于Spring的:
org.springframework.scheduling.quartz.SimpleTriggerBean
org.springframework.scheduling.quartz.CronTriggerBean
前者只支持按照一定频度调用任务,如每隔30分钟运行一次。
后者既支持按照一定频度调用任务,又支持定时任务。 4、org.quartz.Scheduler
代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合,就可以被Scheduler容器调度了。它的方法有start()、shutdown()等方法,负责管理整个调度作业。
等同Spring的: org.springframework.scheduling.quartz.SchedulerFactoryBean
二、Quartz 入门示例
import org.quartz.JobB
import org.quartz.JobD
import org.quartz.S
import org.quartz.SchedulerE
import org.quartz.SchedulerF
import org.quartz.SimpleScheduleB
import org.quartz.T
import org.quartz.TriggerB
import org.quartz.impl.StdSchedulerF
public class Quartz {
public static void main(String[] args) {
// 1、创建JobDetial对象 , 并且设置选项
JobDetail jobDetail= JobBuilder.newJob(MyJob.class).withIdentity(&testJob_1&,&group_1&).build();
// 2、通过 TriggerBuilder 创建Trigger对象
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
triggerBuilder.withIdentity(&trigger_1&, &group_1&);
triggerBuilder.startNow();
// 设置重复次数和间隔时间
triggerBuilder.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(1) //时间间隔
.withRepeatCount(5) // 重复次数
// 设置停止时间
//triggerBuilder.endAt(new Date(System.currentTimeMillis() + 3));
// 创建Trigger对象
Trigger trigger = triggerBuilder.build();
// 3、创建Scheduler对象,并配置JobDetail和Trigger对象
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
// 4、并执行启动、关闭等操作
scheduler.start();
//关闭调度器
//scheduler.shutdown(true);
} catch (SchedulerException e) {
e.printStackTrace();
import java.util.D
import org.quartz.J
import org.quartz.JobExecutionC
import org.quartz.JobExecutionE
public class MyJob implements Job{
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println(new Date() + &: doing something...&);
执行结果:
Wed Aug 03 19:12:53 CST 2016: doing something&
Wed Aug 03 19:12:53 CST 2016: doing something&
Wed Aug 03 19:12:53 CST 2016: doing something&
Wed Aug 03 19:12:53 CST 2016: doing something&
Wed Aug 03 19:12:53 CST 2016: doing something&
Wed Aug 03 19:12:53 CST 2016: doing something&
当把结束时间改为:
// 设置停止时间
triggerBuilder.endAt(new Date(System.currentTimeMillis() + 3));
执行结果:
Wed Aug 03 19:17:12 CST 2016: doing something&
Wed Aug 03 19:17:12 CST 2016: doing something&
Wed Aug 03 19:17:12 CST 2016: doing something&
结果分析:
可以看出,设置重复执行5次,没设置停止时间的时候,执行了6次,当停止时间设置为new Date(System.currentTimeMillis() + 3时, 果只执行了3次。 也就是说当到了停止时间,不管执行的次数是否到达最大次数,都不在执行了。
当添加了关闭调度器:
//关闭调度器
scheduler.shutdown(true);
执行结果:
Wed Aug 03 19:17:12 CST 2016: doing something&
三、Quartz 简单总结
1、scheduler.shutdown(true); // true表示等到本次执行结束 2、为了配置强大时间调度策略,可以研究专门的CronTrigger。 3、整合Spring时,Quartz容器关闭方式有两种方法,一种是关闭- Spring容器,一种是获取到SchedulerFactoryBean实例,然后调用一个shutdown就搞定了。 4、Quartz的JobDetail、Trigger都可以在运行时重新设置,并且在下次调用时候起作用。这就为动态作业的实现提供了依据。你可以将调度时间策略存放到,然后通过数据库数据来设定Trigger,这样就能产生动态的调度。 5、JobDetail不存储具体的实例,但它允许你定义一个实例,JobDetail 又指向JobDataMap。 JobDetail持有Job的详细信息,如它所属的组,名称等信息 6、JobDataMap保存着任务实例的对象,并保持着他们状态信息,它是Map接口的实现,即你可以往里面put和get一些你想存储和获取的信息. 7、scheduler容器包含多个JobDetail和Trigger。scheduler是个容器,容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。
四、Quartz 运行过程
quartz运行时由QuartzSchedulerThread类作为主体,循环执行调度流程。JobStore作为中间层,按照quartz的并发策略执行数据库操作,完成主要的调度逻辑。JobRunShellFactory负责实例化JobDetail对象,将其放入线程池运行。LockHandler负责获取LOCKS表中的数据库锁。
整个quartz对任务调度的时序大致如下:
0.调度器线程run()
1.获取待触发trigger
1.1读取JobDetail信息
1.2读取trigger表中触发器信息并标记为&已获取&
2.触发trigger
2.1确认trigger的状态
2.2读取trigger的JobDetail信息
2.3读取trigger的Calendar信息
2.4更新trigger信息
3实例化并执行Job
3.1从线程池获取线程执行JobRunShell的run方法
我们看到初始化一个调度器需要用工厂类获取实例:
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sch = sf.getScheduler();
// 然后启动:
sch.start();
下面跟进StdSchedulerFactory的getScheduler()方法:
public Scheduler getScheduler() throws SchedulerException {
if (cfg == null) {
initialize();
SchedulerRepository schedRep = SchedulerRepository.getInstance();
//从&调度器仓库&中根据properties的SchedulerName配置获取一个调度器实例
Scheduler sched = schedRep.lookup(getSchedulerName());
if (sched != null) {
if (sched.isShutdown()) {
schedRep.remove(getSchedulerName());
//初始化调度器
sched = instantiate();
我们再看一下 sched = instantiate(); 调度器的初始化方法
- 读取配置资源,
- 生成QuartzScheduler对象,
- 创建该对象的运行线程,并启动线程;
- 初始化JobStore,QuartzScheduler,DBConnectionManager等重要,
- 至此,调度器的初始化工作已完成,初始化工作中quratz读取了数据库中存放的对应当前调度器的锁信息,对应CRM中的表QRTZ2_LOCKS,中的STATE_ACCESS,TRIGGER_ACCESS两个LOCK_NAME.
public void initialize(ClassLoadHelper loadHelper,
SchedulerSignaler signaler) throws SchedulerConfigException {
if (dsName == null) {
throw new SchedulerConfigException(&DataSource name not set.&);
classLoadHelper = loadH
if(isThreadsInheritInitializersClassLoadContext()) {
log.info(&JDBCJobStore threads will inherit ContextClassLoader of thread: & + Thread.currentThread().getName());
initializersLoader = Thread.currentThread().getContextClassLoader();
this.schedSignaler =
// If the user hasn't specified an explicit lock handler, then
// choose one based on CMT/Clustered/UseDBLocks.
if (getLockHandler() == null) {
// If the user hasn't specified an explicit lock handler,
// then we *must* use DB locks with clustering
if (isClustered()) {
setUseDBLocks(true);
if (getUseDBLocks()) {
if(getDriverDelegateClass() != null && getDriverDelegateClass().equals(MSSQLDelegate.class.getName())) {
if(getSelectWithLockSQL() == null) {
//读取数据库LOCKS表中对应当前调度器的锁信息
String msSqlDflt = &SELECT * FROM {0}LOCKS WITH (UPDLOCK,ROWLOCK) WHERE & + COL_SCHEDULER_NAME + & = {1} AND LOCK_NAME = ?&;
getLog().info(&Detected usage of MSSQLDelegate class - defaulting 'selectWithLockSQL' to '& + msSqlDflt + &'.&);
setSelectWithLockSQL(msSqlDflt);
getLog().info(&Using db table-based data access locking (synchronization).&);
setLockHandler(new StdRowLockSemaphore(getTablePrefix(), getInstanceName(), getSelectWithLockSQL()));
getLog().info(
&Using thread monitor-based data access locking (synchronization).&);
setLockHandler(new SimpleSemaphore());
当调用sch.start();方法时, scheduler做了如下工作:
1.通知listener开始启动
2.启动调度器线程
3.启动plugin
4.通知listener启动完成
public void start() throws SchedulerException {
if (shuttingDown|| closed) {
throw new SchedulerException(
&The Scheduler cannot be restarted after shutdown() has been called.&);
// QTZ-212 : calling new schedulerStarting() method on the listeners
// right after entering start()
//通知该调度器的listener启动开始
notifySchedulerListenersStarting();
if (initialStart == null) {
initialStart = new Date();
//启动调度器的线程
this.resources.getJobStore().schedulerStarted();
//启动plugins
startPlugins();
resources.getJobStore().schedulerResumed();
schedThread.togglePause(false);
getLog().info(
&Scheduler & + resources.getUniqueIdentifier() + & started.&);
//通知该调度器的listener启动完成
notifySchedulerListenersStarted();
调度器启动后,调度器的线程就处于运行状态了,开始执行quartz的主要工作&调度任务. 前面已介绍过,任务的调度过程大致分为三步:
1.获取待触发trigger
2.触发trigger
3.实例化并执行Job
而调度过程的三个步骤就承载在QuartzSchedulerThread这个调度器线程类的run()方法中。代码大家可以看一下。我在这里就略过性的支出run()方法中对应上面三个步骤的源码。
触发器的获取,run()方法中获取待触发trigger
调用JobStoreSupport.acquireNextTriggers方法:
//调度器在trigger队列中寻找30秒内一定数目的trigger准备执行调度,
//参数1:nolaterthan = now+3000ms,参数2 最大获取数量,大小取线程池线程剩余量与定义值得较小者
//参数3 时间窗口 默认为0,程序会在nolaterthan后加上窗口大小来选择trigger
triggers = qsRsrcs.getJobStore().acquireNextTriggers(
now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());
参数的意义如下:
参数1:nolaterthan = now+3000ms,即未来30s内将会被触发.
参数2 最大获取数量,大小取线程池线程剩余量与定义值得较小者.
参数3 时间窗口 默认为0,程序会在nolaterthan后加上窗口大小来选择
触发trigger: QuartzSchedulerThread.run()
调用JobStoreSupport.triggersFired方法:
List res = qsRsrcs.getJobStore().triggersFired(triggers);
该方法做了以下工作:
1.获取trigger当前状态
2.通过trigger中的JobKey读取trigger包含的Job信息
3.将trigger更新至触发状态
4.结合calendar的信息触发trigger,涉及多次状态更新
5.更新数据库中trigger的信息,包括更改状态至STATE_COMPLETE,及计算下一次触发时间.
6.返回trigger触发结果的数据传输类TriggerFiredBundle
Job执行过程:QuartzSchedulerThread.run()
qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
shell.initialize(qs);
为每个Job生成一个可运行的RunShell,并放入线程池运行.
在最后调度线程生成了一个随机的等待时间,进入短暂的等待,这使得其他节点的调度器都有机会获取数据库资源.如此就实现了quratz的负载平衡.
这样一次完整的调度过程就结束了.调度器线程进入下一次循环.11:17 提问
quartz 一次触发执行多次job
使用quartz做定时任务,设置执行* 0/5 * * * ? ,任务只有一个触发器
但是触发器触发后,JOB却执行了60多次,就好像触发器一瞬间出发了 60多次一样,有人碰见过吗
有观察了一下日志,我设置的表达式“* 0/5 * * * ”,但是日志显示的是到规定时间后,每一秒触发一回,触发一分钟
有解决方法吗
这个是我建立表达式型触发器时,用的方法,有问题吗??
按赞数排序
Cron表达式生成器:
想多久触发一次,去这个网站配置解析生成啊
0/5 * * * ? 这个Cron表达式 不是每五分钟执行一次吗
你是要每一分钟触发一次的吗
cron:“0 0/1 * * * ? ”
Cron表达式生成器:
0/5 * * * 的意思表示,在5分钟,10分钟,15分钟。。。时,每秒都执行
改成“0 0/5 * * *“, 意思就是每隔5分钟了
我想要的是每5分钟执行一次,而不是每五分钟执行60次
哈哈哈我也碰到了一样的问题,*代表着每,* 0/5 * * *的意思是每过5分钟就每秒执行一次执行60秒
请问解决了么
我也遇到了这个问题
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐quartz中一个job如何对应多个trigger?
[问题点数:40分,结帖人amberleaf]
quartz中一个job如何对应多个trigger?
[问题点数:40分,结帖人amberleaf]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
匿名用户不能发表回复!|博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 sqlserver新建触发器 的文章

 

随机推荐