Quartz.NET简单使用

news/2024/4/30 13:25:57/文章来源:https://blog.csdn.net/BadAyase/article/details/126520232

文章目录

  • 一、Quartz.NET概述
  • 二、Quartz.NET快速上手
    • 1. 下载安装
    • 🔺2. 配置
      • 2.1. Fluent Scheduler Builder API
      • 2.2. 配置文件
    • ⭐3. 启动一个示例程序
      • 3.1. 添加日志
      • 3.2. 试验程序并添加作业
  • 三、教程
    • 1️⃣使用Quartz
    • 2️⃣作业与触发器
      • 2.1. Quartz API
      • 2.2. Jobs和Triggers
      • 2.3. Identities

一、Quartz.NET概述

在这里插入图片描述
Quartz,中文是石英的意思,由此联想到石英钟,利用石英的某些特性制成的钟表。
时间这种东西可以被高精度的计时器具切分为很小份。在每份时间中,我们都可以做一些事情,而怎么安排每份时间做什么事情,就是时间调度。

因此正如上图里描述的那样,Quartz(.NET)是一个.NET开源的调度系统。它原本是流行的Java开源框架,移植到.NET就成Quartz.NET了。当然,这丝毫不影响它的强大。

随便摘几句官网对它的描述,

Quartz. NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems.

小到应用程序,大到企业系统都可以使用它。所以你不用担心,Quartz到底适不适用于你的程序,放心,只要是程序,都可以用它。

这边介绍说它是调度系统,那它可以用来干些什么呢?
在这里插入图片描述
嵌入到程序中使用,作业调度,作业执行,作业持久化,集群,监听&插件。
说这些对于初学者来讲可能扯太远了,因为初学者往往只想要简单使用它。
于我而言,只需要它完成一个定时器的功能,比如在每周的指定时间做一些操作即可。(该功能直接用定时器或者开个线程循环判断也可以实现,只需要循环判断当前时间即可,但这一点也不优雅,而且当这类任务数量庞大时,自己管理起来会很复杂,所以还是有必要学习使用Quartz)。


二、Quartz.NET快速上手

1. 下载安装

NuGet里搜就好了,直接安装即可。
在这里插入图片描述

🔺2. 配置

这部分很重要!Quartz.NET是一个可配置的库。它有两种主要的配置方式(两者不冲突):

这部分很重要是官方文档说的,但是这部分实际上又没那么重要。
如果你和我一样,只是简单地使用它,完全可以不用配置,因为Quartz默认的配置就够用了,
可以直接跳到下一节示例程序。

2.1. Fluent Scheduler Builder API

可以用C# fluent API,或通过向包含配置键和值的调度器工厂(scheduler factory)提供NameValueCollection参数来配置调度器(scheduler)。

Fluent API是C#中的一种写法设计,
底层细节实现就不展开讲了,大家可以找网上的内容看看,不难理解的。
这种写法的优点正如其名一样——流畅的接口,
可以一口气调用一串方法,一气呵成。
写出来的代码往往是这样子:a.b(condition1).c(condition2).d(condition3)…
具体可以看下面例子。

// you can have base properties
var properties = new NameValueCollection();// and override values via builder
IScheduler scheduler = await SchedulerBuilder.Create(properties)// default max concurrency is 10.UseDefaultThreadPool(x => x.MaxConcurrency = 5)// this is the default // .WithMisfireThreshold(TimeSpan.FromSeconds(60)).UsePersistentStore(x =>{// force job data map values to be considered as strings// prevents nasty surprises if object is accidentally serialized and then // serialization format breaks, defaults to falsex.UseProperties = true;x.UseClustering();// there are other SQL providers supported too x.UseSqlServer("my connection string");// this requires Quartz.Serialization.Json NuGet packagex.UseJsonSerializer();})// job initialization plugin handles our xml reading, without it defaults are used// requires Quartz.Plugins NuGet package.UseXmlSchedulingConfiguration(x =>{x.Files = new[] { "~/quartz_jobs.xml" };// this is the defaultx.FailOnFileNotFound = true;// this is not the defaultx.FailOnSchedulingError = true;}).BuildScheduler();await scheduler.Start();

2.2. 配置文件

下列文件用于配置属性:

  • YourApplication.exe.config,使用了quartz-element的配置文件(仅支持完整的.NET Framework)
  • appsettings.json(.NET Core/NET5开始)
  • quartz.config ,该文件在应用程序的根目录中(.NET Core和.NET Framework都可以使用)

可用属性的完整文档在Quartz Configuration Reference获取。

要快速上手,一个基本的quartz.config看起来是这样的:

quartz.scheduler.instanceName = MyScheduler
quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz
quartz.threadPool.maxConcurrency = 3

记得在VS文件属性页上设置“拷贝到输出目录”来使值“始终复制”。否则,如果配置不在构建目录中,将无法被看到。

由该配置创建的调度器具有以下特征:

  • quartz.scheduler.instanceName —— 该调度器的名字为“MyScheduler”。
  • quartz.threadPool.maxConcurrency —— 最多同时运行3个作业(默认是10个)。
  • quartz.jobStore.type —— Quartz的所有数据,比如作业和触发器都保存在内存中。
  • 即使你有一个数据库,并且你想

Tip
事实上,如果你不想定义这些属性,那你就可以不定义它们。Quartz.NET自带健全的默认配置。

⭐3. 启动一个示例程序

不想了解太多有关Quartz的事情,而是想直接上手使用,那看这节就够了。
甚至这节当中的日志打印也不用管。
你需要做的步骤为:

  1. new一个StdSchedulerFactory
  2. 从factory中获取一个scheduler
  3. 启用scheduler,即scheduler.Start()
  4. 创建你的作业JobDetail(这个作业就相当于你要调度执行的方法的类,该类中有个Execute方法就是你想要执行的方法)
  5. 创建一个触发器Trigger(给触发器做一些配置,什么时候触发)
  6. 将触发器和作业绑定

ok,现在你的方法就会按触发器的配置执行了。

		StdSchedulerFactory factory = new StdSchedulerFactory();IScheduler scheduler = await factory.GetScheduler();await scheduler.Start();// 周报表IJobDetail weekReportJob1 = JobBuilder.Create<WeekReportJob>().WithIdentity("weekReportJob1", "reportGroup").Build();ITrigger weekReportTrigger = TriggerBuilder.Create().WithIdentity("weekReportTrigger", "reportGroup").WithSchedule(CronScheduleBuilder.AtHourAndMinuteOnGivenDaysOfWeek(0, 0, DayOfWeek.Monday))//.WithSimpleSchedule(x => x.WithIntervalInSeconds(60).RepeatForever())//.StartNow().Build();await scheduler.ScheduleJob(weekReportJob1, weekReportTrigger);

下列代码先获取了一个调度器实例,然后启动了它,接着关闭了它。

using System;
using System.Threading.Tasks;using Quartz;
using Quartz.Impl;namespace QuartzSampleApp
{public class Program{private static async Task Main(string[] args){// Grab the Scheduler instance from the FactoryStdSchedulerFactory factory = new StdSchedulerFactory();IScheduler scheduler = await factory.GetScheduler();// and start it offawait scheduler.Start();// some sleep to show what's happeningawait Task.Delay(TimeSpan.FromSeconds(10));// and last shut down the scheduler when you are ready to close your programawait scheduler.Shutdown();}}
}

从Quartz 3.0起,当scheduler.Shutdown()后面没有任何代码可执行时,应用程序将会终止,因为没有任何活动的线程。若你想让调度程序在Task.Delay和ShutDown之后继续运行,应该手动阻止程序退出。

现在运行这个程序不会显示任何东西。10秒过后,程序将终止。现在让我们往控制台中添加一些日志打印吧。

3.1. 添加日志

LibLog可以配置为在底层使用不同的日志框架;也就是Log4Net、NLog和Serilog这类的。

当LibLog没有检测到任何其他日志框架存在时,它是静默的。我们可以配置一个自定义日志记录器提供程序,如果你还没有准备好日志框架,它只会将日志记录到控制台并显示输出。

LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());private class ConsoleLogProvider : ILogProvider
{public Logger GetLogger(string name){return (level, func, exception, parameters) =>{if (level >= LogLevel.Info && func != null){Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);}return true;};}public IDisposable OpenNestedContext(string message){throw new NotImplementedException();}public IDisposable OpenMappedContext(string key, object value, bool destructure = false){throw new NotImplementedException();}
}

3.2. 试验程序并添加作业

现在启动这个程序时,我们应该能看到更多的信息了。
在这里插入图片描述
我们需要一个简单的测试作业来测试功能,接下来创建一个HelloJob输出到控制台。

public class HelloJob : IJob
{public async Task Execute(IJobExecutionContext context){await Console.Out.WriteLineAsync("Greetings from HelloJob!");}
}

要使它产生效果,你需要在Start()方法之后、Task.Delay()之前编写它。

// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<HelloJob>().WithIdentity("job1", "group1").Build();// Trigger the job to run now, and then repeat every 10 seconds
ITrigger trigger = TriggerBuilder.Create().WithIdentity("trigger1", "group1").StartNow().WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever()).Build();// Tell quartz to schedule the job using our trigger
await scheduler.ScheduleJob(job, trigger);// You could also schedule multiple triggers for the same job with
// await scheduler.ScheduleJob(job, new List<ITrigger>() { trigger1, trigger2 }, replace: true);

现在,完整的程序如下:

using System;
using System.Threading.Tasks;using Quartz;
using Quartz.Impl;
using Quartz.Logging;namespace QuartzSampleApp
{public class Program{private static async Task Main(string[] args){LogProvider.SetCurrentLogProvider(new ConsoleLogProvider());// Grab the Scheduler instance from the FactoryStdSchedulerFactory factory = new StdSchedulerFactory();IScheduler scheduler = await factory.GetScheduler();// and start it offawait scheduler.Start();// define the job and tie it to our HelloJob classIJobDetail job = JobBuilder.Create<HelloJob>().WithIdentity("job1", "group1").Build();// Trigger the job to run now, and then repeat every 10 secondsITrigger trigger = TriggerBuilder.Create().WithIdentity("trigger1", "group1").StartNow().WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever()).Build();// Tell quartz to schedule the job using our triggerawait scheduler.ScheduleJob(job, trigger);// some sleep to show what's happeningawait Task.Delay(TimeSpan.FromSeconds(60));// and last shut down the scheduler when you are ready to close your programawait scheduler.Shutdown();Console.WriteLine("Press any key to close the application");Console.ReadKey();}// simple log provider to get something to the consoleprivate class ConsoleLogProvider : ILogProvider{public Logger GetLogger(string name){return (level, func, exception, parameters) =>{if (level >= LogLevel.Info && func != null){Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + level + "] " + func(), parameters);}return true;};}public IDisposable OpenNestedContext(string message){throw new NotImplementedException();}public IDisposable OpenMappedContext(string key, object value, bool destructure = false){throw new NotImplementedException();}}}public class HelloJob : IJob{public async Task Execute(IJobExecutionContext context){await Console.Out.WriteLineAsync("Greetings from HelloJob!");}}
}

一个简单的使用示例就完成了,接下来会对其中一些细节进一步展开。

三、教程

1️⃣使用Quartz

在使用调度器之前,你需要对它进行实例化(这谁又能猜到呢?)。为此,你需要一个ISchedulerFactory的实现。

一旦实例化了调度器,你就可以启动它、将它设为待机模式或者关闭它。要注意的是,一旦一个调度器被关闭了,它就不能在没有重新实例化的情况下重启。在调度器启动之前,Triggers(触发器)不会被触发(作业不会执行),在它处于暂停状态时候也一样。

使用Quartz.NET
下面是一个快速开始的代码示例,它实例化和启动一个调度器,并调度一个作业执行:

// construct a scheduler factory using defaults
StdSchedulerFactory factory = new StdSchedulerFactory();// get a scheduler
IScheduler scheduler = await factory.GetScheduler();
await scheduler.Start();// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<HelloJob>().WithIdentity("myJob", "group1").Build();// Trigger the job to run now, and then every 40 seconds
ITrigger trigger = TriggerBuilder.Create().WithIdentity("myTrigger", "group1").StartNow().WithSimpleSchedule(x => x.WithIntervalInSeconds(40).RepeatForever())
.Build();await scheduler.ScheduleJob(job, trigger);// You could also schedule multiple triggers for the same job with
// await scheduler.ScheduleJob(job, new List<ITrigger>() { trigger1, trigger2 }, replace: true);

用fluent API配置调度器

你还可以使用SchedulerBuilder fluent API以代码方式配置调度器。

var sched = await SchedulerBuilder.Create()// default max concurrency is 10.UseDefaultThreadPool(x => x.MaxConcurrency = 5)// this is the default // .WithMisfireThreshold(TimeSpan.FromSeconds(60)).UsePersistentStore(x =>{// force job data map values to be considered as strings// prevents nasty surprises if object is accidentally serialized and then // serialization format breaks, defaults to falsex.UseProperties = true;x.UseClustering();x.UseSqlServer("my connection string");// this requires Quartz.Serialization.Json NuGet packagex.UseJsonSerializer();})// job initialization plugin handles our xml reading, without it defaults are used// requires Quartz.Plugins NuGet package.UseXmlSchedulingConfiguration(x =>{x.Files = new[] { "~/quartz_jobs.xml" };// this is the defaultx.FailOnFileNotFound = true;// this is not the defaultx.FailOnSchedulingError = true;}).BuildScheduler();await scheduler.Start();

正如你所见,使用Quartz.NET并不复杂。接下来,将快速概述作业(job)和触发器,使你能够更充分理解这个例子。

2️⃣作业与触发器

2.1. Quartz API

下面是Quartz API的一些关键接口和类:

  • IScheduler - 与调度器交互的主要API。
  • IJob - 一个你希望由调度器执行的组件所实现的接口。
  • IJobDetail - 用来定义作业的实例。
  • ITrigger - 它定义了如何调度一个作业,一个作业可以有多个关联的触发器。
  • JobBuilder - 用于定义/构建JobDetail实例,该实例定义了作业的实例。
  • TriggerBuilder - 用于定义/构建触发器实例。
  • SchedulerBuilder - 用于定义/构建调度器实例,要求Quartz3.1以后的版本。

在本教程中,为了便于阅读,以下术语可以互换使用:
IScheduler和Scheduler、IJob和Job、IJobDetail和JobDetail、ITrigger和Trigger。

Scheduler的生命周期受其创建(通过SchedulerFactory和对其Shutdown方法的调用)限制。一旦创建了IScheduler接口,就可以用它添加、删除和列出Jobs和Triggers,以及执行其他与调度相关(scheduling-related)的操作(比如暂停触发器)。不过,在使用Start()方法启动之前,Scheduler不会实际操作任何触发器(执行作业)。

Quartz提供了“builder(构建器)”,它定义了域特定语言(Domain Specific Language,简称DSL,有时也称fluent Interface)。在前面章节中,应该看到过它的例子了,这边再展示一小段(就是fluent API吧):

// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<HelloJob>().WithIdentity("myJob", "group1") // name "myJob", group "group1".Build();// Trigger the job to run now, and then every 40 seconds
ITrigger trigger = TriggerBuilder.Create().WithIdentity("myTrigger", "group1").StartNow().WithSimpleSchedule(x => x.WithIntervalInSeconds(40).RepeatForever())            .Build();// Tell quartz to schedule the job using our trigger
await sched.scheduleJob(job, trigger);

这块代码使用JobBuilder构建了作业的定义,使用Fluent Interface创建了IJobDetail。同样,构建触发器的代码也使用了专用于给定触发器类型的TriggerBuilder的fluent Interface和拓展方法。调度的拓展方法有:

  • WithCalendarIntervalSchedule
  • WithCronSchedule
  • WithDailyTimeIntervalSchedule
  • WithSimpleSchedule

DateBuilder类型包含各种方法,用于轻松构造特定时间点的DateTimeOffset实例(例如,下一个偶数小时的时间,比如现在是9:43:27,那么下个目标时间点就是10:00:00)。

2.2. Jobs和Triggers

Job(作业)是一个实现了IJob接口的类,它只有一个简单的方法:

// IJob Interface
namespace Quartz
{public interface IJob{Task Execute(JobExecutionContext context);}
}

当Job的触发器触发时,Execute(…)方法会被调度器的一个工作线程调用。
传递给该方法的JobExecutionContext对象向作业实例提供关于其“运行时”环境的信息——执行它的调度器的句柄、触发执行的触发器的句柄、作业的JobDetail对象以及一些其他项。

JobDetail对象在Job被添加到调度器时由Quartz.NET客户端(即你的程序)创建。它包含了Job的各种属性设置,以及一个JobDataMap,它可用于存储作业类的给定实例的状态信息。它本质上是作业实例的定义。

触发器对象用于触发作业的执行。当你希望调度一个作业时,就实例化一个触发器并“调整”它的属性以达到你想要的调度。触发器还可能有一个与之关联的JobDataMap——这对于向Job传递专用于触发器触发的参数很有用。Quartz发布了几种不同的触发器类型,其中最常用的类型是SimpleTrigger(接口ISimpleTrigger)和CronTrigger(接口ICronTrigger)。

若你想要“一次执行”(在给定时间内只执行一次作业),或者你需要给定时间内触发作业,并让它重复N次,每次执行之间的延迟为T,SimpleTrigger会很方便。
如果你希望触发基于日历的调度——比如“每周五中午”或“每个月的第十天的十点钟”。那么CronTrigger是很有效的。

为什么会有作业和触发器呢?许多作业调度器没有单独的作业和触发器的概念。有些人将“作业”定义为简单的带有一些作业标识符的执行时间(或调度)。另一些人将其定义为很像Quartz的作业与触发器对象结合体的底下。在开发Quartz的过程中,开发者们认为有必要在调度和在调度上执行的作业之间建立一个隔离。这会带来很多好处。

例如,作业能独立于触发器在作业调度器中创建并存储,并且多个触发器可以与同一个作业关联。这种松耦合(loose-coupling)的另一个好处是能够配置在相关触发器过期后仍保留在调度器中的作业,以便稍后可以重新调度它,而不必重新定义它。这也允许修改或替换触发器,而无需重新定义其相关的作业。

2.3. Identities

在向Quartz调度器注册作业和触发器时,将被提供一个标识键(identifying keys)。作业和触发器的键(JobKey和TriggerKey)允许将它们放入“groups(组)”中,这对将作业和触发器组织成“reporting jobs(报告作业)”和“maintain jobs(维护作业)”等类别很有用。作业和触发器的键的名称在组中必须是唯一的。

  • 换句话说,作业或触发器的完整的键(或标识符)是名称和组的组合。

现在你应该对什么是作业和触发器有个大致的概念了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_4239.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2022-8-31 jsp el表达式

jsp <%-- JSP脚本片段:用于在JSP页面写java代码--%> 注意: 1、JSP脚本片段中只能出现java代码,不能出现HTML元素。在 访问JSP时,JSP引擎翻译JSP页面中的脚本片段。 2、JSP脚本片段中的java代码必须严格遵守java的规则 3、一个JSP页面是可以有多…

猿创征文|UDP/TCP网络编程

⭐️前言⭐️ &#x1f349;博客主页&#xff1a; &#x1f341;【如风暖阳】&#x1f341; &#x1f349;精品Java专栏【JavaSE】、【备战蓝桥】、【JavaEE初阶】、【MySQL】、【数据结构】 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&…

Redis主从库网络断连问题——repl_backlog_buffer

主从库间网络断了怎么办&#xff1f; 在 Redis 2.8 之前&#xff0c;如果主从库在命令传播时出现了网络闪断&#xff0c;那么&#xff0c;从库就会和主库重新进行一次全量复制&#xff0c;开销非常大。 从 Redis 2.8 开始&#xff0c;网络断了之后&#xff0c;主从库会采用增量…

hashmap底层原理解析

底层数据结构&#xff0c;1.7与1.8有何不同? 为何要用红黑树&#xff0c;为何一上来不树化&#xff1f;树化阈值为何是8&#xff1f;何时会树化&#xff1f;何时会退化为链表? 链表比较短的时候&#xff0c;查询性能并没有那么低&#xff0c;不用费劲把它转成红黑树&#xff…

项目经理如何做好项目管理中的风险管理

项目中始终有些看不见的风险&#xff0c;这些风险可以成为威胁&#xff0c;也有可能会影响到项目的计划发生重大的变化。 一、项目目标不明确 确定项目目标是项目启动阶段重要的工作之一&#xff0c;要想项目在实施阶段少走弯路&#xff0c;在项目开工前&#xff0c;必须清晰…

信息系统项目管理师Part16-物联网

物联网 1.物联网的两项关键技术 传感器技术、嵌入式技术 2.传感器技术和嵌入式技术 RFID射频识别&#xff1a;可通过无线电信号识别特定目标并读写相关数据&#xff0c;而无需识别系统与特定目标之间建立机械或光学接触。 嵌入式技术&#xff1a;是综合了计算机硬件、传感器技…

猿创征文|OLAP之apache pinot初体验

目录 一、背景 二、介绍 三、特征 四、价值 五、参考组件 组件清单介绍&#xff1a; 1.Controller 2.Server 3.Broker 4.Minion (optional) 六、数据采集 批量数据流程 实时数据流程 查询处理流程 一、背景 最近在熟悉公司内部的埋点采集&#xff0c;发现数据架构…

NK-RTU980 CAP

BSP包中有两个CAP相关的例程&#xff0c;两个例程的区别为获取的图像数据的存储格式不同&#xff0c;planar例程是先存储所有像素点的Y&#xff0c;再存U&#xff0c;再存V。packed例程是每个像素的YVU连续存储。 一、硬件电路 处理器为NUC980DR61Y&#xff0c;封装为64pin&a…

python--转换wrf输出的风场数据为网页可视化的json格式

前言&#xff1a; 一般网页可视化风场中的数据都是json格式&#xff0c;而如果我们希望将wrf模式模拟输出的风场数据在网页中进行展示&#xff0c;这就需要先将wrfoutput数据转换为网页可以识别的json格式。 这里主要需要用到json库&#xff0c;主要的实现方式就是将读取的风场…

微信网课答案公众号题库接口使用

微信网课答案公众号题库接口使用 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&…

亚马逊审核 美国站安全带ASTMF1772安全绳攀岩绳EN892认证流程

1 登山锁扣定义 登山用锁扣是一种带弹簧门的金属环状物&#xff0c;用于在攀岩和登山时快速可逆地连接各部件&#xff0c;是安全系统关键的一部分。 登山用锁扣可用于将绳索固定到设备上&#xff0c;或者将两件或多件设备连接在一起。它们通常由铝或钢制成。这种锁扣具有不同…

ps2021神经ai滤镜无法使用,ps2021没法用神经元滤镜

如何解决ps2021 新版 AI神经滤镜不能用? 网上买正版&#xff0c;更新下就好了&#xff0c;盗版的都会有各种这样的问题。ps2021神经AI滤镜是需简要上传云端&#xff0c;由Adobe官方服务器人工智能运算的。 Ps2021版本新增了Ai神经元滤镜&#xff0c;它不是与软件一起安装的&…

谣言粉碎机?Python验证股市操盘口诀

更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流。 经常炒股的朋友,应该都听说过这段操盘口诀: 早上大跌要买,早上大涨要卖 下午大涨不追,下午大跌次日买 早上大跌不割,不涨不跌睡觉 我们随手百度,也能发现各大主流论坛,充斥着该口…

Spring入门——Eclipse实现HelloWorld程序

前言 疫情影响又延期开学&#xff0c;只能在家上上网课划划水&#xff0c;刚做完spring入门的一个小作业&#xff0c;来做个总结分享&#xff0c;我也是个刚入门的小白&#xff0c;还望大佬们指点。 步入主题 环境 eclipse/spring-tool-suite-3 jdk1.8.0_221 另外&#xff0…

Linux :mysql数据库自动备份

Linux &#xff1a;mysql数据库自动备份前言使用shell脚本进行数据库的定时备份确定备份数据库备份shell脚本定时shell脚本前言 当项目发布到服务器上后&#xff0c;接下来考虑到就是如何做好数据库的数据备份。为的就是防止服务器突然异常崩溃&#xff0c;而导致的数据丢失问…

使用上下游思维实现系统解耦

在软件开发领域&#xff0c;解耦这个词相信大家都不陌生。在面向对象的语境下&#xff0c;我们会应用SOLID原则来构建高内聚低耦合的应用&#xff0c;实现模块间的解耦&#xff1b;在复杂业务系统分析和建模时&#xff0c;会通过DDD的战略和战术设计帮助划分领域并实现分布式系…

Java毕业设计-校园活动赞助与宣传管理系统

&#x1f525;作者主页&#xff1a;疯狂行者&#x1f525; &#x1f496;✌java领域优质创作者,专注于Java技术领域技术交流✌&#x1f496; &#x1f496;文末获取源码&#x1f496; 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1…

(分布式缓存)Redis持久化

一、RDB持久化 首先需要在Linux系统中安装一个Redis&#xff0c;如果尚未安装的同学&#xff0c;可以参考下面链接教程安装先&#xff1a; (73条消息) 单机安装Redis_其然乐衣的博客-CSDN博客 修改配置文件 创建一个数据 因为设置了只要5秒内有一次修改就会触发一次备份数据&am…

最全 Burp Suite 最新付费稳定版安装教程

介绍 Burp Suite是web应用程序渗透测试集成平台。从应用程序攻击表面的最初映射和分析,到寻找和利用安全漏洞等过程,所有工具为支持整体测试程序而无缝地在一起工作。 平台中所有工具共享同一robust框架,以便统一处理HTTP请求、持久性、认证、上游代理、日志记录、报警和可扩…

《QDebug 2022年8月》

一、Qt Widgets 问题交流 1.QWidget鼠标事件穿透 对于一些透明或者半透明的QWidget&#xff0c;可能需要点击其下方的按钮或其他组件&#xff0c;但是QWidget本身是会接收这些鼠标事件的&#xff0c;需要一些额外的处理。下面是百度到的一些方法&#xff1a; 方式A.设置setA…