zoukankan      html  css  js  c++  java
  • 【Quartz】持久化到数据库【五】

      前言

        我们做到这里已经对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

    最后就是大结局了,让我们看下运行结果吧:

  • 相关阅读:
    A program file was not specified in the launch configuration.
    Effective C++条款38: 决不要重新定义继承而来的缺省参数值
    进程控制块
    Effective C++条款37: 决不要重新定义继承而来的非虚函数
    Effective C++条款42: 明智地使用私有继承
    迭代的是人,递归的是神(第一篇——递归调用的分析)
    Effective C++条款36: 区分接口继承和实现继承
    进程上下文
    进程的层次结构 ——进程组捕捉信号
    SQL语句的并集UNION,交集JOIN(内连接,外连接),交叉连接(CROSS JOIN笛卡尔积),差集(NOT IN)
  • 原文地址:https://www.cnblogs.com/yanbigfeg/p/9050901.html
Copyright © 2011-2022 走看看