动态设置定时任务(数据库持久化定时信息,Springboot 整合quartz)

1、场景

  1.1 发布消息、问卷等信息时,发布者可以指定星期、月份的具体时间进行定时发布(cron 触发器)

  1.2 设置当天或指定日期的时间范围内,指定时间间隔执行任务。(目前该功能未研究,可参考如下说明即可实现。)

  1.3 其他定时功能可根据不同的任务触发器进行实现。(未研究

2、定时任务框架(Quartz )

2.1 选型

  简单地使用注解方式的定时任务已无法满足上述场景需求。网上也找了很多定时框架,如 cn.hutool(Java 工具类库)、XXL-JOB,hutool 研究一下感觉无法满足,且代码写起来不够简洁,就放弃了。XXL-JOB 看着介绍起来烦琐就不研究了,最后看了一下 Quartz 介绍和相关博客,要用上很多 Quartz 相关的表,但我不需要这些表,一开始打算放弃的,然后查看了Springboot 整合Quartz 后,灵感突然来了。嗯~不需要关联的表,自己创建业务表即可。嗯!感觉可以。

2.2 Quartz 介绍

   Quartz 定时任务据我了解可分为Trigger(触发器)Job(任务)Scheduler(调度器),定时任务的逻辑大体为:创建触发器和任务,并将其加入到调度器中,如下图所示:

在这里插入图片描述

  Trigger 有五种触发器:

  • SimpleTrigger 触发器:需要在特定的日期/时间启动,且以指定的间隔时间(单位毫秒)重复执行 n 次任务,如 :在 9:00 开始,每隔1小时,每隔几分钟,每隔几秒钟执行一次 。没办法指定每隔一个月执行一次(每月的时间间隔不是固定值)
  • CalendarIntervalTrigger 触发器:指定从某一个时间开始,以一定的时间间隔(单位有秒,分钟,小时,天,月,年,星期)执行的任务。
  • DailyTimeIntervalTrigger 触发器:指定每天的某个时间段内,以一定的时间间隔执行任务。并且支持指定星期。如:指定每天 9:00 至 18:00 ,每隔 70 秒执行一次,并且只要周一至周五执行。
  • CronTrigger 触发器:基于日历的任务调度器,即指定星期、日期的某时间执行任务。
  • NthIncludedDayTrigger 触发器:不同时间间隔的第 n 天执行任务。比如,在每个月的第 15 日处理财务发票记帐,同样设定双休日或者假期。

说明:2 中介绍只了解皮毛,研究了怎么用,如何实现想要功能而已,有不同意见可评论,勿喷。

3、实现

   基于场景 1.1,使用 CronTrigger 触发器最合适。我想的实现逻辑如下:创建一张定时任务的表来存储动态生成的 cron 表达式,接着创建触发器、任务,再启动调度器。程序在重启时,读取定时任务表,将之前生成的任务重新调度起来。以定时发布问卷为例

3.1 定时任务表
CREATE TABLE `que_task_info` (
  `task_id` varchar(60) NOT NULL COMMENT '定时任务ID(触发器名)',
  `type` int(1) NOT NULL COMMENT '作业类型: 1/每天; 2/每周; 3/每月',
  `minute` int(2) DEFAULT 0 COMMENT '指定分钟',
  `hour` int(2) DEFAULT 0 COMMENT '指定小时',
  `last_day_of_month` int(1) DEFAULT NULL COMMENT '指定一个月的最后一天:0/不指定;1/指定',
  `week_days` varchar(20) DEFAULT NULL COMMENT '指定一周哪几天,用英文‘,’隔开:1/星期天; 2/...3/..   ; 7/星期六',
  `month_days` varchar(100) DEFAULT NULL COMMENT '指定一个月的哪几天,用英文‘,’隔开',
  `cron` varchar(255) NOT NULL COMMENT '定时任务表达式',
  `start_time` datetime NOT NULL COMMENT '定时任务开始时间',
  `end_time` datetime NOT NULL COMMENT '定时任务结束时间',
  `trigger_group` varchar(60) NOT NULL COMMENT '定时任务触发器所在组名(问卷ID)',
  `job_name` varchar(60) NOT NULL COMMENT '定时任务名称',
  `status` int(1) NOT NULL DEFAULT '1' COMMENT '状态:0/过期或未执行;1/执行中',
  PRIMARY KEY (`task_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='问卷定时任务表'

3.2 pom.xml

  添加如下依赖:

        <!--   定时任务     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

3.3 任务调度器类

  封装一个自己的任务调度器类,含有创建触发器、更新触发器、移除触发器、创建任务、启动调度器功能方法。

import cn.hutool.core.date.DateUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 *  定时任务调度器
 * @author pky
 */
@Slf4j
@Component
@AllArgsConstructor
public class TaskScheduler {

    private final Scheduler scheduler;

    /**
     * 创建触发器的响应信息(时间错误信息)
     */
    private final static String CORN_RESPONSE_TIME_ERR = "will never fire";
    /**
     * 默认触发器时间错误提示
     */
    private final static String DEFAULT_TIME_ERR_MSG = "截止时间必须大于其中最小的有效指定定期时间";
    /**
     * 含月末的触发器的错误提示
     */
    private final static String ERR_MSG_OF_LAST_MONTH_DAY = "截止时间不可小于月末时间";


    /**
     * 启动调度器
     * @param jobDetail 任务
     * @param trigger 任务触发器
     */
    public void startScheduler(JobDetail jobDetail, Trigger trigger, String cron) {
        try {
            String name = jobDetail.getKey().getName();
            String group = jobDetail.getKey().getGroup();
            JobDetail schedulerJobDetail = scheduler.getJobDetail(new JobKey(name, group));
            scheduler.scheduleJob(jobDetail, trigger);
            if(schedulerJobDetail == null) {
                scheduler.start();
            }
            log.info("启动调度器成功");
        }
        catch (Exception e) {
            log.error(e.toString());
            String message = e.getMessage();
            if(StringUtils.isNotBlank(message) && message.contains(CORN_RESPONSE_TIME_ERR)) {
                if(cron.contains("L")) {
                    throw new ServiceException(ERR_MSG_OF_LAST_MONTH_DAY);
                }
                throw new ServiceException(DEFAULT_TIME_ERR_MSG);
            }
            throw new ServiceException("启动调度器失败");
        }
    }

    /**
     * 获取任务
     * @param jobName 任务名
     * @param jobGroup 任务所在组名
     * @param cla 任务实体
     * @param <T> 继承 Job 的任务实体类
     * @return 任务
     */
    public <T extends Job> JobDetail getJob(String jobName, String jobGroup, Class<T> cla) {
        try {
            JobDetail jobDetail = scheduler.getJobDetail(new JobKey(jobName, jobGroup));
            if(jobDetail != null) {
                return jobDetail;
            }
            return JobBuilder.newJob(cla).withIdentity(jobName, jobGroup).build();
        }
        catch (Exception e) {
            throw new ServiceException("获取任务失败");
        }
    }

    /**
     * 创建 cron 触发器
     * @param triggerName 触发器名
     * @param triggerGroup 触发器所在组名
     * @param startTime 触发器开始时间
     * @param endTime 触发器关闭时间
     * @param cron cron 表达式
     * @return 触发器
     */
    public Trigger buildCronTrigger(String triggerName, String triggerGroup, Date startTime, Date endTime, String cron) {
        // 触发器
        return TriggerBuilder.newTrigger()
                .withIdentity(triggerName, triggerGroup)
                // 开始日期
                .startAt(DateUtil.parseDateTime(TimeUtil.dateTimeFormat(startTime)))
                // 关闭日期
                .endAt(DateUtil.parseDateTime(TimeUtil.dateTimeFormat(endTime)))
                // 触发的具体时间 cron 表达式,并且项目启动时不触发,到cron时间才触发
                .withSchedule(CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing())
                .build();
    }

    /**
     * 更新 cron 触发器
     * @param triggerName 触发器名
     * @param triggerGroup 触发器组名
     * @return true/成功,false/失败
     */
    public Boolean updatedCronTrigger(String triggerName, String triggerGroup, Date startTime, Date endTime, String cron) {
        // 1、获取旧的触发器
        TriggerKey oldTrigger = new TriggerKey(triggerName, triggerGroup);
        // 2、创建新的触发器
        Trigger newTrigger = buildCronTrigger(triggerName, triggerGroup, startTime, endTime, cron);
        // 3、替换触发器
        try {
            scheduler.rescheduleJob(oldTrigger, newTrigger);
            log.info("更新触发器成功");
            return true;
        }
        catch (Exception e) {
            log.error(e.toString());
            String message = e.getMessage();
            if(StringUtils.isNotBlank(message) && message.contains(CORN_RESPONSE_TIME_ERR)) {
            	// 含有L的单独处理
                if(cron.contains("L")) {
                    throw new ServiceException(ERR_MSG_OF_LAST_MONTH_DAY);
                }
                throw new ServiceException(DEFAULT_TIME_ERR_MSG);
            }
            throw new ServiceException("更新 cron 触发器失败");
        }
    }

    /**
     * 删除触发器
     * @param triggerName 触发器名
     * @param triggerGroup 触发器组名
     * @return true/成功,false/失败
     */
    public Boolean removeTrigger(String triggerName, String triggerGroup) {
        try {
            TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroup);
            // 停止触发器
            scheduler.pauseTrigger(triggerKey);
            // 移除触发器
            boolean flag = scheduler.unscheduleJob(triggerKey);
            log.info("移除触发器成功");
            return flag;
        }
        catch (Exception e) {
            throw new ServiceException("移除触发器失败");
        }
    }
}

3.4 任务类

  定时任务执行的主体,实现 Job 接口

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.transaction.annotation.Transactional;

/**
 * 定时问卷发布任务
 * @author pky
 */
public class QueReleaseJob implements Job {

    /**
     * 执行任务
     * @param context 任务执行器上下文,含有触发器名等信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void execute(JobExecutionContext context) {
        // todo 要执行的任务逻辑
        System.out.println("任务执行.....");
    }

}

3.5 cron 工具类

  封装一个属于场景 1.1 的 cron 表达式生成工具类。

import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * cron 表达式工具类
 * @author pky
 */
public class CronUtil {
    /**
     * 每天
     */
    private static final int DAY_JOB_TYPE = 1;
    /**
     * 每周
     */
    private static final int WEEK_JOB_TYPE = 2;
    /**
     * 每月
     */
    private static final int MONTH_JOB_TYPE = 3;

    /**
     *构建Cron表达式
     * @param jobType 作业类型: 1/每天; 2/每周; 3/每月
     * @param minute 指定分钟
     * @param hour 指定小时
     * @param lastDayOfMonth 指定一个月的最后一天:0/不指定;1/指定
     * @param weekDays 指定一周哪几天:1/星期天; 2/...3/..   ; 7/星期六
     * @param monthDays 指定一个月的哪几天
     *@return String
     */
    public static String createCronExpression(Integer jobType, Integer minute, Integer hour, Integer lastDayOfMonth, List<Integer> weekDays, List<Integer> monthDays){
        StringBuilder cronExp = new StringBuilder();
        // 秒
        cronExp.append("0 ");
        // 指定分钟,为空则默认0分
        cronExp.append(minute == null ? "0" : minute).append(" ");
        // 指定小时,为空则默认0时
        cronExp.append(hour == null ? "0" : hour).append(" ");
        // 每天
        if(jobType == DAY_JOB_TYPE){
            // 日
            cronExp.append("* ");
            // 月
            cronExp.append("* ");
            // 周
            cronExp.append("?");
        }
        else if(lastDayOfMonth != null && lastDayOfMonth == 1) {
            // 日
            cronExp.append("L ");
            // 月
            cronExp.append("* ");
            // 周
            cronExp.append("?");
        }
        // 按每周
        else if(weekDays != null && jobType == WEEK_JOB_TYPE){
            // 日
            cronExp.append("? ");
            // 月
            cronExp.append("* ");
            // 一个周的哪几天
            cronExp.append(StringUtils.join(weekDays, ","));
        }
        // 按每月
        else if(monthDays != null && jobType == MONTH_JOB_TYPE){
            // 日
            cronExp.append(StringUtils.join(monthDays, ",")).append(" ");
            // 月
            cronExp.append("* ");
            // 周
            cronExp.append("?");
        }
        else {
            cronExp.append("* ").append("* ").append("?");
        }
        return cronExp.toString();
    }
}

说明:cron 表达式规则可自行查阅

3.6 请求参数

总参数
参数名必选类型说明
jobTypeYint作业类型: 1/每天; 2/每周; 3/每月
timesYList时间列表
minuteYint指定分钟
hourYint指定小时
lastDayOfMonthNint指定一个月的最后一天:0/不指定;1/指定
weekDaysNList指定一周哪几天:1/星期天; 2/…3/… ; 7/星期六
monthDaysNList指定一个月的哪几天

注:weekDays 和 monthDays 同时存在时,根据 jobType 进行取舍。jobType=2对应weekDays,jobTyp=3对应monthDays,jobType=1时,weekDays和monthDays都无效。

times 时间列表参数
参数名必选类型说明
minuteYint指定分钟
hourYint指定小时
请求示例
  • POST
  • ContentType : application/json
{
    "jobType":2,
    "times":[
        {
            "minute":"15",
            "hour":"8"
        },
        {
            "minute":"00",
            "hour":"18"
        }
    ],
    "weekDays":[2,6]
}

3.7 创建触发器、任务组,启动调度器

3.7.1 逻辑代码

  以下有些实体类不一一展示,理解代码很容易就可构造出来,若实在看不懂,可私信或评论。

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 采集定时发布表达式表业务逻辑(collect_cron)
 *
 * @author pky
 */
@Service
@AllArgsConstructor
public class QueTaskServiceImpl extends ServiceImpl<QueTaskMapper, QueTask> implements QueTaskService {

    TaskScheduler taskScheduler;

    /**
     * 保存定时发布信息并启动任务
     *
     * @param regularVo 定时信息【接收】实体
     * @param startTime 任务开始时间
     * @param endTime 任务结束时间
     * @param triggerGroup 触发器组名(问卷ID)
     * @param status 0/保存(未触发);1/发布(触发)
     * @return 定时任务列表
     */
    @Override
    public List<QueTask> saveAndStartTask(QueRegularVo regularVo, Date startTime, Date endTime, String triggerGroup, Integer status) {
        // 先删除定时信息
        delByTriggerGroup(triggerGroup);
        // 1、转换一个月指定日期的格式,以英文“,”隔开
        String monthDayStr = regularVo.getMonthDays() == null ? "" : StringUtils.join(regularVo.getMonthDays(), ",");
        // 2、转换一个星期指定哪几天的格式,以英文“,”隔开,,周日为1,周六为7
        String weekDayStr = regularVo.getWeekDays() == null ? "" : StringUtils.join(regularVo.getWeekDays(), ",");
        // 3、设置定时发布信息
        List<QueTask> queTaskList = new ArrayList<>();
        // 设置每月月末的触发器
        if(regularVo.getLastDayOfMonth() == 1) {
	            List<QueTask> lastMonthDayTasks = setQueTaskParam(regularVo, "?", "*", 1, startTime, endTime, triggerGroup, status);
            queTaskList.addAll(lastMonthDayTasks);
        }
        // 设置指定星期或每月日期的触发器
        if(StringUtils.isNotBlank(monthDayStr) || StringUtils.isNotBlank(weekDayStr)) {
            List<QueTask> tasks = setQueTaskParam(regularVo, weekDayStr, monthDayStr, 0, startTime, endTime, triggerGroup, status);
            queTaskList.addAll(tasks);
        }
        // 4、批量保存
        saveBatch(queTaskList);
        // 5、添加触发器(1为发布)
        if (status == 1) {
            queTaskList.forEach(task -> {
                // 创建任务组
                JobDetail job = taskScheduler.getJob(task.getJobName(), QueTaskRunner.RELEASE_JOB_GROUP, QueReleaseJob.class);
                // 创建触发器
                Trigger trigger = taskScheduler.buildCronTrigger(task.getTaskId(), task.getTriggerGroup(), task.getStartTime(), task.getEndTime(), task.getCron());
                // 启动触发器
                taskScheduler.startScheduler(job, trigger, task.getCron());
            });
        }
        return queTaskList;
    }

    /**
     * 设置问卷定时任务参数列表
     * @param regularVo 定时信息【接收】实体
     * @param weekDayStr 一个星期指定哪几天的格式,以英文“,”隔开,周日为1,周六为7
     * @param monthDayStr 一个月指定日期的格式,以英文“,”隔开
     * @param lastDayOfMonth 指定一个月的最后一天:0/不指定;1/指定
     * @param startTime 任务开始时间
     * @param endTime 任务结束时间
     * @param triggerGroup 触发器组名(采集ID)
     * @param status 0/保存(未触发);1/发布(触发)
     * @return 定时任务列表
     */
    private List<QueTask> setQueTaskParam(QueRegularVo regularVo, String weekDayStr, String monthDayStr, Integer lastDayOfMonth, Date startTime, Date endTime, String triggerGroup, Integer status) {
        List<QueTask> queTaskList = new ArrayList<>();
        List<QueRegularTimeVo> times = regularVo.getTimes();
        for (QueRegularTimeVo timeVo : times) {
            QueTaskqueTask= new QueTask();
            queTask.setType(regularVo.getJobType());
            queTask.setHour(timeVo.getHour());
            queTask.setMinute(timeVo.getMinute());
            queTask.setLastDayOfMonth(lastDayOfMonth);
            queTask.setWeekDays(weekDayStr);
            queTask.setMonthDays(monthDayStr);
            // 创建 cron 表达式(规则是:单个时间对应多个日期)
            String cronStr = CronUtil.createCronExpression(regularVo.getJobType(), timeVo.getMinute(), timeVo.getHour(), lastDayOfMonth, regularVo.getWeekDays(), regularVo.getMonthDays());
            queTask.setCron(cronStr);
            queTask.setStartTime(startTime);
            queTask.setEndTime(endTime);
            queTask.setTriggerGroup(triggerGroup);
            queTask.setJobName(UUIDUtil.getUUID());
            queTask.setStatus(status);
            queTaskList.add(collectTask);
        }
        return queTaskList;
    }

    /**
     * 根据触发器组名(问卷ID)删除定时信息
     * @param triggerGroup 触发器组名(问卷ID)
     */
    @Override
    public void delByTriggerGroup(String triggerGroup) {
        lambdaUpdate().eq(QueTask::getTriggerGroup, triggerGroup).remove();
    }
}

3.7.2 数据持久化后

在这里插入图片描述

3.8 自定义定时任务配置类

  为啥要自定义配置类呢?因为3.7 中,无法注入 TaskScheduler,具体不知道什么原因,因此就手动注入一下 bean。

import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * task 框架配置类
 * @author pky
 */
@Configuration
public class QuartzConfig {

    /**
     * 手动将自定义的 TaskScheduler 注入到 spring 容器中
     * @param scheduler quartz 框架的调度器
     * @return 自定义 quartz 框架的程序调度器
     */
    @Bean
    public TaskScheduler getScheduler(Scheduler scheduler) {
        return new TaskScheduler(scheduler);
    }
}

3.8 重启项目时启动定时任务

  上述代码中,虽然在逻辑代码中,每发布一条定时问卷,都会生成一条或多条定时任务。但程序宕机重启后,还需将持久化中的定时任务加入到调度器中。

import org.apache.commons.collections4.CollectionUtils;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 问卷定时任务执行器
 * @author pky
 */
@Component
public class QueTaskRunner implements ApplicationRunner {

    /**
     * 问卷模块的任务组名
     */
    public static final String RELEASE_JOB_GROUP = "queReleaseJobGroup";
    private final QueTaskService queTaskService;
    private final TaskScheduler taskScheduler;

    public QueTaskRunner(QueTaskService queTaskService, TaskScheduler taskScheduler) {
        this.queTaskService= queTaskService;
        this.taskScheduler = taskScheduler;
    }

    @Override
    public void run(ApplicationArguments args) {
        // 1、获取执行中的定时任务信息(1有效的定时任务)
        List<QueTask> tasks = queTaskService.getQueCronByStatus(1);
        if(CollectionUtils.isEmpty(tasks)) {
            return;
        }
        // 2、创建任务
        for(QueTask task : tasks) {
            JobDetail jobDetail = taskScheduler.getJob(task.getJobName(), RELEASE_JOB_GROUP, QueReleaseJob.class);
            // 获取触发器
            Trigger trigger = taskScheduler.buildCronTrigger(task.getTaskId(), task.getTriggerGroup(), task.getStartTime(), task.getEndTime(), task.getCron());
            // 启动调度器
            try {
                taskScheduler.startScheduler(jobDetail, trigger, task.getCron());
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

问卷相关信息表这里不一一展示,可根据自己的需求来实现。

4、效果

  程序启动时,控制台打印。
在这里插入图片描述

  定时任务时间设置 UI 图。
在这里插入图片描述
在这里插入图片描述
  发布后,到点出发问卷发布。

在这里插入图片描述

源码

https://download.csdn.net/download/qq_34369588/87445397?spm=1001.2014.3001.5501

基本分享完,有改善的地方,欢迎私信或留言评论。

  • 5
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
在 C# 中,可以使用 Quartz.NET 来实现定时任务,同时支持数据库持久化Quartz.NET 是一个功能强大且灵活的开源作业调度库,可以用于创建定时任务和计划任务,支持数据库持久化和集群部署等高级功能。 要使用 Quartz.NET 实现数据库持久化,需要先创建一个用于存储调度程序数据的数据库表,可以使用 Quartz.NET 提供的 SQL 脚本来创建表。然后在应用程序中配置 Quartz.NET,指定数据库类型和连接字符串等信息。示例如下: ```csharp using Quartz; using Quartz.Impl; using Quartz.Impl.AdoJobStore; using Quartz.Spi; using System; using System.Collections.Specialized; class Program { static void Main() { Console.WriteLine("Starting scheduler..."); // 创建一个调度程序实例 ISchedulerFactory schedulerFactory = new StdSchedulerFactory(GetSchedulerProperties()); IScheduler scheduler = schedulerFactory.GetScheduler().Result; // 启动调度程序 scheduler.Start(); Console.WriteLine("Scheduler started."); // 创建一个作业实例 IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("job1", "group1") .Build(); // 创建一个触发器实例,每秒钟触发一次 ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(1) .RepeatForever()) .Build(); // 将作业和触发器添加到调度程序中 scheduler.ScheduleJob(job, trigger); // 等待用户按下 Enter 键退出 Console.ReadLine(); // 关闭调度程序 scheduler.Shutdown(); Console.WriteLine("Scheduler stopped."); } static NameValueCollection GetSchedulerProperties() { // 配置调度程序属性,指定数据库持久化和相关参数 NameValueCollection properties = new NameValueCollection(); properties["quartz.scheduler.instanceName"] = "MyScheduler"; properties["quartz.scheduler.instanceId"] = "AUTO"; properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"; properties["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz"; properties["quartz.jobStore.dataSource"] = "default"; properties["quartz.dataSource.default.provider"] = "SqlServer-20"; properties["quartz.dataSource.default.connectionString"] = "Server=(local);Database=Quartz;Trusted_Connection=True;"; return properties; } } public class HelloJob : IJob { public void Execute(IJobExecutionContext context) { Console.WriteLine("Hello, Quartz.NET!"); } } ``` 这个示例会创建一个调度程序实例,然后创建一个作业实例和触发器实例,并将它们添加到调度程序中。作业类 HelloJob 实现了 IJob 接口,用于定义作业执行的逻辑。在 GetSchedulerProperties 方法中,配置了调度程序属性,指定了数据库类型和连接字符串等信息。在这个示例中,使用的是 SQL Server 数据库。 需要注意的是,在使用 Quartz.NET 进行数据库持久化时,需要保证数据库连接可靠和高效,同时需要考虑并发执行的问题。可以适当地调整作业和触发器的参数,以达到最优的性能和可靠性。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值