前言
我们做到这里已经对Quartz定时器组件已经是学会了基本的使用了。但是我们有没有想过任务开启之后万一断掉了,当机了我们怎么办,你是否还想继续执行原先的任务。我们普通的创建是把任务放在内存中存储,如果内存被释放掉,任务也就消失了,那怎么办哪,不得不说这个组件还是很厉害的。他已经帮我们想过了解方案---就是放到数据库。
Quartz插一嘴:
quartz在任务中分为两种:有状态和无状态执行。
有状态:对于同一个 trigger 来说,有状态的 job 不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。所有我自己理解为串行的顺序执行(自己怎么好记怎么理解 哈哈)
无状态:无状态任务一般指可以并发的任务,即任务之间是独立的,不会互相干扰。就是各自干各自的。
数据库概貌:
首先上一下sql脚本下载地址:sql数据库rar文件下载
表结构瞅一瞅:
下面是表代表的大致意思吧:
表名 |
描述 |
QRTZ_BLOB_TRIGGERS |
作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候) |
QRTZ_CALENDARS |
以 Blob 类型存储 Quartz 的 Calendar 信息 |
QRTZ_CRON_TRIGGERS |
存储 Cron Trigger,包括 Cron 表达式和时区信息 |
QRTZ_FIRED_TRIGGERS |
存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息 |
QRTZ_JOB_DETAILS |
存储每一个已配置的 Job 的详细信息 |
QRTZ_LOCKS |
存储程序的非观锁的信息(假如使用了悲观锁) |
QRTZ_PAUSED_TRIGGER_GRPS |
存储已暂停的 Trigger 组的信息 |
QRTZ_SCHEDULER_STATE |
存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例(假如是用于一个集群中) |
QRTZ_SIMPLE_TRIGGERS |
存储简单的 Trigger,包括重复次数,间隔,以及已触的次数 |
QRTZ_SIMPROP_TRIGGERS |
|
QRTZ_TRIGGERS |
存储已配置的 Trigger 的信息 |
代码部分:
工具都有了那就干活吧,既然我上面说了任务分为有状态和无状态,那正好借这个例子一起给介绍一下。首先还是我们的老朋友任务的创建:
这是一个无状态任务
public class ServerJob : IJob { private const string Count = "count"; public virtual void Execute(IJobExecutionContext context) { JobKey jobKey = context.JobDetail.Key; try { // 如果任务是恢复的任务的话 if (context.Recovering) { WritTxt.WriteFile("serversql", jobKey+":恢复打印"); } else { WritTxt.WriteFile("serversql", jobKey+":启动打印"); } JobDataMap data = context.JobDetail.JobDataMap; int count; if (data.ContainsKey(Count)) { count = data.GetInt(Count); } else { count = 0; } count++; data.Put(Count, count); WritTxt.WriteFile("serversql", string.Format("结束: {0} done at {1} 累计数 #{2}", jobKey, DateTime.Now.ToString("r"), count)); } catch (Exception ex) { } } }
下面是一个有状态任务,因为本人比较懒所有就不写新任务了,直接继承了无状态任务事件。
[PersistJobDataAfterExecution] //代表当前任务是否有状态 [DisallowConcurrentExecution]//代表任务不允许并发 public class ServerJobState : ServerJob { }
下面就是我们要说的重点了;数据库配置
只需要在实例化调度器前把我们的数据库配置传进去就好了。
/// <summary> /// 持久化属性 /// </summary> NameValueCollection properties = new NameValueCollection(); public ExampleServer() { properties["quartz.scheduler.instanceName"] = "TestScheduler"; properties["quartz.scheduler.instanceId"] = "instance_one"; properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz"; properties["quartz.threadPool.threadCount"] = "5"; properties["quartz.threadPool.threadPriority"] = "Normal"; properties["quartz.jobStore.misfireThreshold"] = "60000"; properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"; properties["quartz.jobStore.useProperties"] = "false"; properties["quartz.jobStore.dataSource"] = "default"; properties["quartz.jobStore.tablePrefix"] = "QRTZ_"; properties["quartz.jobStore.clustered"] = "true"; properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"; properties["quartz.dataSource.default.connectionString"] = "Server=(local);Database=quartz;Trusted_Connection=True;"; properties["quartz.dataSource.default.provider"] = "SqlServer-20"; // First we must get a reference to a scheduler ISchedulerFactory sf = new StdSchedulerFactory(properties); Scheduler = sf.GetScheduler(); }
然后就是运行测试了,这里我用了不同的形式返回了调度器和调度工厂。这样子也挺好用的,可以把以前的那种方法改成这种。
/// <summary> /// 调度工厂 /// </summary> private static StdSchedulerFactory SchedulerFactory { get; set; } /// <summary> /// 调度接口 /// </summary> private static IScheduler Scheduler { get; set; } #region 0.测试 public void Run() { string schedId = Scheduler.SchedulerInstanceId; IJobDetail job = JobBuilder.Create<ServerJob>() .WithIdentity("ServerJob", schedId) .RequestRecovery() .Build(); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("serverTrigger", schedId) .WithCronSchedule("0/10 * * * * ?") //5秒执行一次 .Build(); //已存在就不重复添加 try { Scheduler.ScheduleJob(job, trigger); } catch (Exception ex) { } IJobDetail jobState = JobBuilder.Create<ServerJobState>() .WithIdentity("ServerJobSatte", schedId) .RequestRecovery() .Build(); ITrigger triggerState = TriggerBuilder.Create() .WithIdentity("serverTriggerSatte", schedId) .WithCronSchedule("0/10 * * * * ?") //5秒执行一次 .Build(); //已存在就不重复添加 try { Scheduler.ScheduleJob(jobState, triggerState); } catch (Exception ex) { } //启动 Scheduler.Start(); } #endregion
最后就是大结局了,让我们看下运行结果吧: