本文基于.net6的框架
quartz官网:点我跳转
第一步:安装NuGet包
工具-》nuget包管理器-》程序包管理器控制台-》输入以下代码后回车安装
Install-Package Quartz
第二步:配置文件
打开Program.cs类,加入以下代码,位置在builder变量下面
using Quartz;
using Quartz.Impl;
builder.Services.AddControllersWithViews();
builder.Services.AddMvc();
builder.Services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();//注册ISchedulerFactory的实例。
第三步:控制器代码
声明两个全局变量,添加有参的构造函数为变量赋值,添加任务调度函数
private readonly ISchedulerFactory _schedulerFactory;
private IScheduler _scheduler;
public LoginController(LibraryContext context, ISchedulerFactory schedulerFactory)
{
_schedulerFactory = schedulerFactory;
}
//任务调度
public async Task Begin()
{
_scheduler = await _schedulerFactory.GetScheduler();
//开启调度器
await _scheduler.Start();
//创建一个触发器
var trigger = TriggerBuilder.Create()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever())//间隔2秒 一直执行
.UsingJobData("key1", 321) //通过在Trigger中添加参数值
.WithIdentity("mytrigger", "group")
.Build();
//创建任务
var jobDetail = JobBuilder.Create<MyJob>()
.WithIdentity("myjob")
.Build();
jobDetail.JobDataMap.Add("context", _context);
//将触发器和任务器绑定到调度器中
await _scheduler.ScheduleJob(jobDetail, trigger);
}
触发器里触发条件可以任意修改,调节成自己需要的时分秒。
第四步:添加任务类
using Quartz;
namespace QuartzDemo.Models
{
/// <summary>
/// 创建IJob的实现类,并实现Excute方法
/// </summary>
[PersistJobDataAfterExecution]//更新JobDetail的JobDataMap的存储副本,以便下一次执行这个任务接收更新的值而不是原始存储的值
public class MyJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
//var jobData = context.JobDetail.JobDataMap;//获取Job中的参数
var triggerData = context.Trigger.JobDataMap;//获取Trigger中的参数
var data = context.MergedJobDataMap;//获取Job和Trigger中合并的参数
var value1 = triggerData.GetInt("key1");
//var value2 = triggerData.GetString("key2");
return Task.Run(() =>
{
Console.WriteLine(value1);
Console.WriteLine("01");
});
}
}
}
这样在你需要的地方调用begin()函数,任务就会跑起来了。比如这里就会在控制台每2s打印123和01。然后就可以在myjob里编写你需要定时调度的任务。接下来是我用到的定时执行存储过程,需要连接数据库,不需要的友友看到这里就可以了。
第五步:添加操作数据库的任务
由于对数据库操作需要声明上下文,这里我们的任务调度进的是job类的无参构造函数,所以没办法传递上下文的值,在几经周折之后,我把数据库连接字符串改成了单例模式,然后成功获取到了数据库的数据,但是正常情况下不应该采取这种方法,会引起其他错误,以下是使用单例模式的错误示例。
1、修改Program.cs类里数据库连接字符串变为单例模式
2、在任务调度控制器任务调度函数里创建任务时将数据库上下文的值保存下来作为参数传递给myjob类jobDetail.JobDataMap.Add("context", _context);
记得先声明上下文并注入。
3、最后在myjob类里编写调用数据库的函数并调用就好啦。
改完之后引起了其他错误,后面在求助大佬在一顿操作后使用了自动注入,按以下配置:
1.修改Program.cs类,注意将数据库单例模式改掉
// 1.将默认ServiceProviderFactory指定为AutofacServiceProviderFactory
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
// 2.自动注册
Assembly assembly = Assembly.Load("BookManage01");
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().InstancePerDependency();
});
2、然后将myjob类中获取上下文的方式改为自动注入
//执行任务
public async Task Execute(IJobExecutionContext context)
{
var _context = IocManager.Instance.GetService<LibraryContext>();
await AddOverdueMsg(_context);
}
然后就解决了,实现了使用任务调度定期执行数据库语句。
解决这个问题接触到的知识点:使用Quartz进行任务调度,单例模式,构造函数,.net的生命周期,自动注入,服务解析。
对于本文的错误或不足欢迎指出!