前言
我們做到這里已經對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}\n 累計數 #{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
最后就是大結局了,讓我們看下運行結果吧: