Topshelf + QuartzNet 实现挂载在 WIndows Services 中的定时任务
直接贴代码了:
首先我们可以把所有的 Job 放到一个单独的 DLL 中,好处是可以共享这些业务 Job。比如我们新建一个 QuartzNetDemo.WinService.Jobs 的类库。
然后,我们再先定义一个 WriteTextToFileJob 的任务:
public class WriteTextToFileJob : IJob
{
// Fields
private static readonly string TypeName = typeof(WriteTextToFileJob).FullName; // Methods
public virtual void Execute(IJobExecutionContext context)
{
FileUtil.AppendFormat("=================================任务开始:{0}=================================", new object[] { TypeName });
FileUtil.AppendFormat("当前时间:{0},正在运行...", new object[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
if (context.JobDetail.JobDataMap.ContainsKey("UserName"))
{
string str = context.JobDetail.JobDataMap.GetString("UserName");
FileUtil.AppendFormat("当前时间:{0},接受到参数 \"{1}\" 的值等于 {2}", new object[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), "UserName", str });
}
if (context.JobDetail.JobDataMap.ContainsKey("Msg"))
{
string str2 = context.JobDetail.JobDataMap.GetString("Msg");
FileUtil.AppendFormat("当前时间:{0},接受到参数 \"{1}\" 的值等于 {2}", new object[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), "Msg", str2 });
}
FileUtil.AppendFormat("当前时间:{0},准备暂停 {1} 秒钟...", new object[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), });
Thread.Sleep(TimeSpan.FromSeconds(5.0));
FileUtil.AppendFormat("当前时间:{0},已经运行完毕!", new object[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
FileUtil.AppendFormat("=================================任务结束:{0}=================================", new object[] { TypeName });
}
}
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- 注意:App.config 文件更改后,无须重新安装 Windows Services,只需要重启就可以了 -->
<configSections>
<!-- 注册 Quartz 节点 -->
<section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<!-- 注册 log4net -->
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<!-- 配置 log4net -->
<log4net configSource="log4net.config" />
<appSettings>
<!-- 下面是配置 Windows 服务的相关参数 -->
<add key="quartz.server.serviceName" value="QuartzNetDemoWinService" />
<add key="quartz.server.serviceDisplayName" value="QuartzNetDemoWinService" />
<add key="quartz.server.serviceDescription" value="负责项目的定时调度任务" />
</appSettings>
<!-- Quartz 配置 -->
<quartz>
<!-- 基本参数配置 -->
<add key="quartz.scheduler.instanceName" value="QuartzNetDemo.WinService" />
<add key="quartz.scheduler.instanceId" value="AUTO" />
<add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
<add key="quartz.threadPool.threadCount" value="" />
<add key="quartz.threadPool.threadPriority" value="Normal" />
<!-- 下面是配置把 Quartz 相关的任务和触发器保存在数据库中 -->
<add key="quartz.jobStore.useProperties" value="true" />
<add key="quartz.jobStore.clustered" value="true" />
<add key="quartz.jobStore.misfireThreshold" value="" />
<add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
<add key="quartz.jobStore.tablePrefix" value="QRTZ_" />
<add key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz" />
<add key="quartz.jobStore.dataSource" value="myDS" />
<add key="quartz.dataSource.myDS.connectionString" value="Data Source=.;Initial Catalog=TestDB;User ID=sa;Password=123456;" />
<add key="quartz.dataSource.myDS.provider" value="SqlServer-20" />
<!-- 下面是配置可以远程访问
<add key="quartz.scheduler.exporter.type" value="Quartz.Simpl.RemotingSchedulerExporter, Quartz"/>
<add key="quartz.scheduler.exporter.port" value=""/>
<add key="quartz.scheduler.exporter.bindName" value="QuartzScheduler"/>
<add key="quartz.scheduler.exporter.channelType" value="tcp"/>
<add key="quartz.scheduler.exporter.channelName" value="httpQuartz"/>
<add key="quartz.scheduler.exporter.rejectRemoteRequests" value="true"/>
-->
<!-- 下面是 XML 注册任务(是否可以不配置) -->
<add key="quartz.plugin.xml.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz" />
<add key="quartz.plugin.xml.fileNames" value="~/quartz_jobs.xml" />
<!-- 下面是触发器历史记录插件 -->
<add key="quartz.plugin.triggHistory.type" value="Quartz.Plugin.History.LoggingJobHistoryPlugin" />
<!-- 下面是 XML 任务初始化 - 单位为秒 -->
<add key="quartz.plugin.jobInitializer.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin" />
<add key="quartz.plugin.jobInitializer.fileNames" value="quartz_jobs.xml" />
<add key="quartz.plugin.jobInitializer.failOnFileNotFound" value="true" />
<add key="quartz.plugin.jobInitializer.scanInterval" value="" />
</quartz>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
quartz_jobs.xml
<?xml version="1.0" encoding="utf-8" ?>
<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0"> <processing-directives>
<overwrite-existing-data>true</overwrite-existing-data>
</processing-directives> <schedule> <job>
<name>WriteTextToFileJob</name>
<group>jobGroup1</group>
<description>jobDesciption1</description>
<job-type>QuartzNetDemo.WinService.Jobs.WriteTextToFileJob, QuartzNetDemo.WinService.Jobs</job-type>
<durable>true</durable>
<recover>false</recover>
<job-data-map>
<entry>
<key>UserName</key>
<value>周星驰</value>
</entry>
<entry>
<key>Msg</key>
<value>Hello world,欢迎使用 Quartz.net 调度组件</value>
</entry>
</job-data-map>
</job> <trigger>
<simple>
<name>WriteTextToFileJobTrigger</name>
<group>triggerGroup1</group>
<description>SimpleTriggerDescription</description>
<job-name>WriteTextToFileJob</job-name>
<job-group>jobGroup1</job-group>
<start-time>--28T18::.0Z</start-time>
<end-time>--04T18::.0Z</end-time>
<misfire-instruction>SmartPolicy</misfire-instruction>
<repeat-count></repeat-count>
<repeat-interval></repeat-interval>
</simple>
</trigger> </schedule> </job-scheduling-data>
log4net.config
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\log_" />
<param name="AppendToFile" value="true" />
<!-- <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'"/> 这句是按照年月文件夹分类 -->
<param name="DatePattern" value="yyyy-MM-dd_HH".log"" />
<param name="RollingStyle" value="Date" />
<param name="StaticLogFileName" value="false" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %x %m %n" />
<!--每条日志末尾的文字说明-->
<!--输出格式-->
<!--样例:-- ::, [] INFO Fujica.PackingPlatform.WebUI.MainClass [(null)] - info-->
<conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别: %-5level %n出错类: %file 在第 %line 行 %n描述:%message%newline %n"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="FATAL" />
</filter>
</appender>
<!-- Admin 访问信息 -->
<appender name="AdminLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\admin_log_" />
<param name="AppendToFile" value="true" />
<!-- <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'"/> 这句是按照年月文件夹分类 -->
<param name="DatePattern" value="yyyy-MM-dd".log"" />
<param name="RollingStyle" value="Date" />
<param name="StaticLogFileName" value="false" />
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %x %m %n" />
<!--每条日志末尾的文字说明-->
<!--输出格式-->
<!--样例:-- ::, [] INFO Fujica.PackingPlatform.WebUI.MainClass [(null)] - info-->
<conversionPattern value="%newline %n记录时间:%date %n线程ID:[%thread] %n日志级别: %-5level %n出错类: %file 在第 %line 行 %n描述:%message%newline %n"/>
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="FATAL" />
</filter>
</appender>
<logger name="adminLogger" additivity="false">
<level value="ALL" />
<appender-ref ref="AdminLogFileAppender" />
</logger>
<root>
<level value="ALL" />
<appender-ref ref="AdminLogFileAppender" />
<appender-ref ref="LogFileAppender" />
</root>
</log4net>
SchedulerServer.cs
using log4net.Config;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace QuartzNetDemo.WinService
{
public class SchedulerServer
{
// Fields
private readonly StdSchedulerFactory _schedulerFactory = new StdSchedulerFactory(); // Methods
public void Start()
{
Console.WriteLine("Starting scheduler...");
XmlConfigurator.Configure();
this._schedulerFactory.GetScheduler().Start();
} public void Stop()
{
if (this._schedulerFactory != null) this._schedulerFactory.GetScheduler().Shutdown(false);
}
}
}
Configuration.cs
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using System.Text; namespace QuartzNetDemo.WinService
{
public class Configuration
{
// Fields
private static readonly NameValueCollection configuration = ((NameValueCollection) ConfigurationManager.GetSection("appSettings"));
private const string DefaultServiceDescription = "负责项目的定时调度任务";
private const string DefaultServiceDisplayName = "QuartzNetDemoWinService";
private const string DefaultServiceName = "QuartzNetDemoWinService";
private const string KeyServiceDescription = "quartz.server.serviceDescription";
private const string KeyServiceDisplayName = "quartz.server.serviceDisplayName";
private const string KeyServiceName = "quartz.server.serviceName";
private const string PrefixServerConfiguration = "quartz.server"; // Methods
private static string GetConfigurationOrDefault(string configurationKey, string defaultValue)
{
string retValue = null;
if (configuration != null) retValue = configuration[configurationKey];
if (retValue == null || retValue.Trim().Length == ) retValue = defaultValue;
return retValue;
} // Properties
public static string ServiceDescription
{
get
{
return GetConfigurationOrDefault(KeyServiceDescription, DefaultServiceDescription);
}
} public static string ServiceDisplayName
{
get
{
return GetConfigurationOrDefault(KeyServiceDisplayName, DefaultServiceDisplayName);
}
} public static string ServiceName
{
get
{
return GetConfigurationOrDefault(KeyServiceName, DefaultServiceName);
}
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Topshelf;
using Topshelf.HostConfigurators;
using Topshelf.ServiceConfigurators; namespace QuartzNetDemo.WinService
{
class Program
{
static void Main(string[] args)
{
HostFactory.Run(delegate(HostConfigurator x)
{
x.Service<SchedulerServer>( (ServiceConfigurator<SchedulerServer> s) =>
{
s.ConstructUsing(name => new SchedulerServer());
s.WhenStarted<SchedulerServer>(tc => tc.Start());
s.WhenStopped<SchedulerServer>(tc => tc.Stop());
});
x.RunAsLocalSystem();
x.SetDescription(Configuration.ServiceDescription);
x.SetDisplayName(Configuration.ServiceDisplayName);
x.SetServiceName(Configuration.ServiceName);
});
}
}
}
Quartz.NET 官方的 tables_sqlServer.sql
-- this script is for SQL Server and Azure SQL USE [enter_db_name_here]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)
ALTER TABLE [dbo].[QRTZ_TRIGGERS] DROP CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)
ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] DROP CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)
ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISFOREIGNKEY') = 1)
ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] DROP CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS
GO IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QRTZ_JOB_LISTENERS_QRTZ_JOB_DETAILS]') AND parent_object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_LISTENERS]'))
ALTER TABLE [dbo].[QRTZ_JOB_LISTENERS] DROP CONSTRAINT [FK_QRTZ_JOB_LISTENERS_QRTZ_JOB_DETAILS] IF EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N'[dbo].[FK_QRTZ_TRIGGER_LISTENERS_QRTZ_TRIGGERS]') AND parent_object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGER_LISTENERS]'))
ALTER TABLE [dbo].[QRTZ_TRIGGER_LISTENERS] DROP CONSTRAINT [FK_QRTZ_TRIGGER_LISTENERS_QRTZ_TRIGGERS] IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CALENDARS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_CALENDARS]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_CRON_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_CRON_TRIGGERS]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_BLOB_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_BLOB_TRIGGERS]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_FIRED_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_FIRED_TRIGGERS]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_PAUSED_TRIGGER_GRPS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS]
GO IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_JOB_LISTENERS]') AND type in (N'U'))
DROP TABLE [dbo].[QRTZ_JOB_LISTENERS] IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SCHEDULER_STATE]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_SCHEDULER_STATE]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_LOCKS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_LOCKS]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGER_LISTENERS]') AND type in (N'U'))
DROP TABLE [dbo].[QRTZ_TRIGGER_LISTENERS] IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_JOB_DETAILS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_JOB_DETAILS]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPLE_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS]
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_SIMPROP_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].QRTZ_SIMPROP_TRIGGERS
GO IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[QRTZ_TRIGGERS]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
DROP TABLE [dbo].[QRTZ_TRIGGERS]
GO CREATE TABLE [dbo].[QRTZ_CALENDARS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[CALENDAR_NAME] [NVARCHAR] (200) NOT NULL ,
[CALENDAR] [VARBINARY](MAX) NOT NULL
)
GO CREATE TABLE [dbo].[QRTZ_CRON_TRIGGERS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[TRIGGER_NAME] [NVARCHAR] (150) NOT NULL ,
[TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL ,
[CRON_EXPRESSION] [NVARCHAR] (120) NOT NULL ,
[TIME_ZONE_ID] [NVARCHAR] (80)
)
GO CREATE TABLE [dbo].[QRTZ_FIRED_TRIGGERS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[ENTRY_ID] [NVARCHAR] (140) NOT NULL ,
[TRIGGER_NAME] [NVARCHAR] (150) NOT NULL ,
[TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL ,
[INSTANCE_NAME] [NVARCHAR] (200) NOT NULL ,
[FIRED_TIME] [BIGINT] NOT NULL ,
[SCHED_TIME] [BIGINT] NOT NULL ,
[PRIORITY] [INTEGER] NOT NULL ,
[STATE] [NVARCHAR] (16) NOT NULL,
[JOB_NAME] [NVARCHAR] (150) NULL ,
[JOB_GROUP] [NVARCHAR] (150) NULL ,
[IS_NONCONCURRENT] BIT NULL ,
[REQUESTS_RECOVERY] BIT NULL
)
GO CREATE TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL
)
GO CREATE TABLE [dbo].[QRTZ_SCHEDULER_STATE] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[INSTANCE_NAME] [NVARCHAR] (200) NOT NULL ,
[LAST_CHECKIN_TIME] [BIGINT] NOT NULL ,
[CHECKIN_INTERVAL] [BIGINT] NOT NULL
)
GO CREATE TABLE [dbo].[QRTZ_LOCKS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[LOCK_NAME] [NVARCHAR] (40) NOT NULL
)
GO CREATE TABLE [dbo].[QRTZ_JOB_DETAILS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[JOB_NAME] [NVARCHAR] (150) NOT NULL ,
[JOB_GROUP] [NVARCHAR] (150) NOT NULL ,
[DESCRIPTION] [NVARCHAR] (250) NULL ,
[JOB_CLASS_NAME] [NVARCHAR] (250) NOT NULL ,
[IS_DURABLE] BIT NOT NULL ,
[IS_NONCONCURRENT] BIT NOT NULL ,
[IS_UPDATE_DATA] BIT NOT NULL ,
[REQUESTS_RECOVERY] BIT NOT NULL ,
[JOB_DATA] [VARBINARY](MAX) NULL
)
GO CREATE TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[TRIGGER_NAME] [NVARCHAR] (150) NOT NULL ,
[TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL ,
[REPEAT_COUNT] [INTEGER] NOT NULL ,
[REPEAT_INTERVAL] [BIGINT] NOT NULL ,
[TIMES_TRIGGERED] [INTEGER] NOT NULL
)
GO CREATE TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[TRIGGER_NAME] [NVARCHAR] (150) NOT NULL ,
[TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL ,
[STR_PROP_1] [NVARCHAR] (512) NULL,
[STR_PROP_2] [NVARCHAR] (512) NULL,
[STR_PROP_3] [NVARCHAR] (512) NULL,
[INT_PROP_1] [INT] NULL,
[INT_PROP_2] [INT] NULL,
[LONG_PROP_1] [BIGINT] NULL,
[LONG_PROP_2] [BIGINT] NULL,
[DEC_PROP_1] [NUMERIC] (13,4) NULL,
[DEC_PROP_2] [NUMERIC] (13,4) NULL,
[BOOL_PROP_1] BIT NULL,
[BOOL_PROP_2] BIT NULL,
[TIME_ZONE_ID] [NVARCHAR] (80) NULL
)
GO CREATE TABLE [dbo].[QRTZ_BLOB_TRIGGERS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[TRIGGER_NAME] [NVARCHAR] (150) NOT NULL ,
[TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL ,
[BLOB_DATA] [VARBINARY](MAX) NULL
)
GO CREATE TABLE [dbo].[QRTZ_TRIGGERS] (
[SCHED_NAME] [NVARCHAR] (120) NOT NULL ,
[TRIGGER_NAME] [NVARCHAR] (150) NOT NULL ,
[TRIGGER_GROUP] [NVARCHAR] (150) NOT NULL ,
[JOB_NAME] [NVARCHAR] (150) NOT NULL ,
[JOB_GROUP] [NVARCHAR] (150) NOT NULL ,
[DESCRIPTION] [NVARCHAR] (250) NULL ,
[NEXT_FIRE_TIME] [BIGINT] NULL ,
[PREV_FIRE_TIME] [BIGINT] NULL ,
[PRIORITY] [INTEGER] NULL ,
[TRIGGER_STATE] [NVARCHAR] (16) NOT NULL ,
[TRIGGER_TYPE] [NVARCHAR] (8) NOT NULL ,
[START_TIME] [BIGINT] NOT NULL ,
[END_TIME] [BIGINT] NULL ,
[CALENDAR_NAME] [NVARCHAR] (200) NULL ,
[MISFIRE_INSTR] [INTEGER] NULL ,
[JOB_DATA] [VARBINARY](MAX) NULL
)
GO ALTER TABLE [dbo].[QRTZ_CALENDARS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_CALENDARS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[CALENDAR_NAME]
)
GO ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_CRON_TRIGGERS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
)
GO ALTER TABLE [dbo].[QRTZ_FIRED_TRIGGERS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_FIRED_TRIGGERS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[ENTRY_ID]
)
GO ALTER TABLE [dbo].[QRTZ_PAUSED_TRIGGER_GRPS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_PAUSED_TRIGGER_GRPS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[TRIGGER_GROUP]
)
GO ALTER TABLE [dbo].[QRTZ_SCHEDULER_STATE] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_SCHEDULER_STATE] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[INSTANCE_NAME]
)
GO ALTER TABLE [dbo].[QRTZ_LOCKS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_LOCKS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[LOCK_NAME]
)
GO ALTER TABLE [dbo].[QRTZ_JOB_DETAILS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_JOB_DETAILS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[JOB_NAME],
[JOB_GROUP]
)
GO ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_SIMPLE_TRIGGERS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
)
GO ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_SIMPROP_TRIGGERS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
)
GO ALTER TABLE [dbo].[QRTZ_TRIGGERS] WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_TRIGGERS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
)
GO ALTER TABLE [dbo].QRTZ_BLOB_TRIGGERS WITH NOCHECK ADD
CONSTRAINT [PK_QRTZ_BLOB_TRIGGERS] PRIMARY KEY CLUSTERED
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
)
GO ALTER TABLE [dbo].[QRTZ_CRON_TRIGGERS] ADD
CONSTRAINT [FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
) REFERENCES [dbo].[QRTZ_TRIGGERS] (
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
) ON DELETE CASCADE
GO ALTER TABLE [dbo].[QRTZ_SIMPLE_TRIGGERS] ADD
CONSTRAINT [FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
) REFERENCES [dbo].[QRTZ_TRIGGERS] (
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
) ON DELETE CASCADE
GO ALTER TABLE [dbo].[QRTZ_SIMPROP_TRIGGERS] ADD
CONSTRAINT [FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS] FOREIGN KEY
(
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
) REFERENCES [dbo].[QRTZ_TRIGGERS] (
[SCHED_NAME],
[TRIGGER_NAME],
[TRIGGER_GROUP]
) ON DELETE CASCADE
GO ALTER TABLE [dbo].[QRTZ_TRIGGERS] ADD
CONSTRAINT [FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS] FOREIGN KEY
(
[SCHED_NAME],
[JOB_NAME],
[JOB_GROUP]
) REFERENCES [dbo].[QRTZ_JOB_DETAILS] (
[SCHED_NAME],
[JOB_NAME],
[JOB_GROUP]
)
GO CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP)
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP)
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME)
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP)
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE)
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE)
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE)
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME)
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME)
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME)
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE)
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE) CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME)
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY)
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP)
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP)
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP)
GO
运行后生成的日志比如:admin_log_2018-09-21.log
记录时间:2018-09-21 15:52:22,249
线程ID:[QuartzNetDemo.WinService_Worker-2]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:=================================任务开始:QuartzNetDemo.WinService.Jobs.WriteTextToFileJob================================= 记录时间:2018-09-21 15:52:22,295
线程ID:[QuartzNetDemo.WinService_Worker-2]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:22,正在运行... 记录时间:2018-09-21 15:52:22,296
线程ID:[QuartzNetDemo.WinService_Worker-2]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:22,接受到参数 "UserName" 的值等于 周星驰 记录时间:2018-09-21 15:52:22,296
线程ID:[QuartzNetDemo.WinService_Worker-2]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:22,接受到参数 "Msg" 的值等于 Hello world,欢迎使用 Quartz.net 调度组件 记录时间:2018-09-21 15:52:22,297
线程ID:[QuartzNetDemo.WinService_Worker-2]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:22,准备暂停 5 秒钟... 记录时间:2018-09-21 15:52:25,192
线程ID:[QuartzNetDemo.WinService_Worker-3]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:=================================任务开始:QuartzNetDemo.WinService.Jobs.WriteTextToFileJob================================= 记录时间:2018-09-21 15:52:25,193
线程ID:[QuartzNetDemo.WinService_Worker-3]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:25,正在运行... 记录时间:2018-09-21 15:52:25,196
线程ID:[QuartzNetDemo.WinService_Worker-3]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:25,接受到参数 "UserName" 的值等于 周星驰 记录时间:2018-09-21 15:52:25,197
线程ID:[QuartzNetDemo.WinService_Worker-3]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:25,接受到参数 "Msg" 的值等于 Hello world,欢迎使用 Quartz.net 调度组件 记录时间:2018-09-21 15:52:25,198
线程ID:[QuartzNetDemo.WinService_Worker-3]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:25,准备暂停 5 秒钟... 记录时间:2018-09-21 15:52:27,298
线程ID:[QuartzNetDemo.WinService_Worker-2]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:27,已经运行完毕! 记录时间:2018-09-21 15:52:27,300
线程ID:[QuartzNetDemo.WinService_Worker-2]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:=================================任务结束:QuartzNetDemo.WinService.Jobs.WriteTextToFileJob================================= 记录时间:2018-09-21 15:52:28,191
线程ID:[QuartzNetDemo.WinService_Worker-4]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:=================================任务开始:QuartzNetDemo.WinService.Jobs.WriteTextToFileJob================================= 记录时间:2018-09-21 15:52:28,193
线程ID:[QuartzNetDemo.WinService_Worker-4]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:28,正在运行... 记录时间:2018-09-21 15:52:28,194
线程ID:[QuartzNetDemo.WinService_Worker-4]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:28,接受到参数 "UserName" 的值等于 周星驰 记录时间:2018-09-21 15:52:28,195
线程ID:[QuartzNetDemo.WinService_Worker-4]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:28,接受到参数 "Msg" 的值等于 Hello world,欢迎使用 Quartz.net 调度组件 记录时间:2018-09-21 15:52:28,197
线程ID:[QuartzNetDemo.WinService_Worker-4]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:28,准备暂停 5 秒钟... 记录时间:2018-09-21 15:52:30,200
线程ID:[QuartzNetDemo.WinService_Worker-3]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:30,已经运行完毕! 记录时间:2018-09-21 15:52:30,202
线程ID:[QuartzNetDemo.WinService_Worker-3]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:=================================任务结束:QuartzNetDemo.WinService.Jobs.WriteTextToFileJob================================= 记录时间:2018-09-21 15:52:31,191
线程ID:[QuartzNetDemo.WinService_Worker-5]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:=================================任务开始:QuartzNetDemo.WinService.Jobs.WriteTextToFileJob================================= 记录时间:2018-09-21 15:52:31,193
线程ID:[QuartzNetDemo.WinService_Worker-5]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:31,正在运行... 记录时间:2018-09-21 15:52:31,194
线程ID:[QuartzNetDemo.WinService_Worker-5]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:31,接受到参数 "UserName" 的值等于 周星驰 记录时间:2018-09-21 15:52:31,197
线程ID:[QuartzNetDemo.WinService_Worker-5]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:31,接受到参数 "Msg" 的值等于 Hello world,欢迎使用 Quartz.net 调度组件 记录时间:2018-09-21 15:52:31,198
线程ID:[QuartzNetDemo.WinService_Worker-5]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:31,准备暂停 5 秒钟... 记录时间:2018-09-21 15:52:33,199
线程ID:[QuartzNetDemo.WinService_Worker-4]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:当前时间:2018-09-21 15:52:33,已经运行完毕! 记录时间:2018-09-21 15:52:33,201
线程ID:[QuartzNetDemo.WinService_Worker-4]
日志级别: INFO
出错类: D:\WorkSpace\QuartzNetDemo.WinService\QuartzNetDemo.WinService.Jobs\FileUtil.cs 在第 22 行
描述:=================================任务结束:QuartzNetDemo.WinService.Jobs.WriteTextToFileJob=================================
运行效果图:
这个一个利用 Windows Service 挂载 Quartz (定时调度,也叫定时任务)的例子。
1. Windows Service 的名称和描述可以在 App.config 中的 appSettings 中配置。
2. 该 Windows Service 中的 Quartz 已经配置了持久化任务(即把任务信息保存到数据库),所以需要提前建立好数据库(建库脚本参考 Quartz.net 官方说明),并且配置连接字符串。
3. App.config 文件更改后,无须重新安装 Windows Services,只需要重启就可以了。
4. 通过在 quartz_jobs.xml 文件中注册任务,即可以不通过修改代码来完成“动态”注册任务,比如增加一个类库,编译后把 DLL 复制到 Windows Service 所在的目录下,可以不重启 Windows 服务。
5. 可以观察,当改变了 quartz_jobs.xml 文件中的配置后,打印出的日志信息的变化。
6. 我们在 quartz_jobs.xml 配置的 repeat-interval=3000,即 3 秒执行一次,但在 WriteTextToFileJob 中我们通过 Thread.Sleep(TimeSpan.FromSeconds(5)); 延迟了 5 秒,那么就会存在多个实例交错执行的情况,请观察日志。
7. 在 Quartz 的官方示例 example12 中有一个 RemoteServerExample、RemoteClientExample 例子,即可以远程注册任务,但要注意,需要把 Client 项目的 Job 所引用的所有程序集复制到 Server 所在的 Bin 目录,要不然会运行时会抛出无法找到 DLL 异常。且服务端和客户端所引用的 Quartz 的版本必须一致。Quartz 内部是通过 .NET Remoting 来实现的,把 Client 中的 Job 的元数据序列化给 Server 端,然后 Server 端再去反射、调用。
谢谢浏览!
Topshelf + QuartzNet 实现挂载在 WIndows Services 中的定时任务的更多相关文章
- Windows 系统文件夹目录挂载到 Linux服务器中
在Windows系统文件上传到Linux服务器时有时候很麻烦,因为Linux无界面的系统不像Windows系统一样,可以直接复制粘贴,下面方法可以解决Windows系统文件拷贝到Linux服务器. 1 ...
- 用C#创建Windows服务(Windows Services)
用C#创建Windows服务(Windows Services) 学习: 第一步:创建服务框架 创建一个新的 Windows 服务项目,可以从Visual C# 工程中选取 Windows 服务(W ...
- 当程序以Windows Services形式启动时当前路径不对
当程序以Windows Services形式启动时当前路径不对 @(操作系统)[博客|dotNet] 很多时候我们需要将我们的程序写成利用Windows服务的形式来让它能够自启动.今天遇到一个问题,当 ...
- 解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离
在某国外大型汽车公司BI项目中,有一个子项目,需要通过大屏幕展示销售报表,程序需要自动启动和关闭.开发人员在开发过程中,发现在Win7的service中不能直接操作UI进程,调查过程中,发现如 ...
- [转]解决vista和win7在windows服务中交互桌面权限问题:穿透Session 0 隔离
服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分.我们可以把服务想像成一种特殊的应用程序,它随系统的“开启-关闭”而“开始-停止”其工作内容,在这期间无需任何 ...
- Windows Services Windows Services的操作
Windows Services的操作 一.服务的创建: 1.新建项目——Windows服务 2.这是每个人都会犯的错误,新建一个项目后,都会按F5(运行),就会出现如下错误: 3.安装服务有很多种方 ...
- linux挂载本地windows分区或目录
linux挂载本地windows分区或目录 一.linux挂载本地windows硬盘分区 向虚拟机Centos添加本地windows硬盘 注:(添加物理硬盘后,在centos操作会直接写入本地硬盘) ...
- 使用Topshelf组件构建简单的Windows服务
很多时候都在讨论是否需要了解一个组件或者一个语言的底层原理这个问题,其实我个人觉得,对于这个问题,每个人都有自己的看法,个人情况不同,选择的方式也就会不同了.我个人觉得无论学习什么,都应该尝试着去了解 ...
- windows 服务中托管asp.net core
在windows 服务中托管asp.net core SDK 2.1.300 官方示例 1.添加运行标识符 xml <PropertyGroup> <TargetFramework& ...
随机推荐
- PHP入门了解
1.五个基本概念 1.1静态页面和动态页面 静态页面:服务器不执行的页面 动态页面:服务器执行的页面 1.2客户端和服务器端 客户端:浏览器就是客户端 服务器端:给浏览者提供服务 1.3端 ...
- DataGridView中在新增行时怎样设置每个Cell单元格的字体样式
场景 DataGridView怎样实现添加.删除.上移.下移一行: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10281414 ...
- 设置view的layer属性方法
1.需要导入QuartzCore.framewoork框架到工程2.在文件中导入#import 3.设置 必须导入的空间 #import<QuartzCore/QuartzCore.h> ...
- 5.JavaCC官方入门指南-概述
一.前言 在最开始使用JavaCC的时候,从网上查询了许多资料,但是网上的资料水平是参差不齐的,走了许多弯路,不得已自己查阅了英文版官网文档.令我伤心的是最后我回过头来再看那些博客资料时,发现其实 ...
- MySQL 主从复制(实时热备)原理与配置
MySQL是现在普遍使用的数据库,但是如果宕机了必然会造成数据丢失.为了保证MySQL数据库的可靠性,就要会一些提高可靠性的技术.MySQL主从复制可以做到实时热备数据.本文介绍MySQL主从复制原理 ...
- CentOS7设置开机自启动方式
方式一: # 在/etc/rc.d/rc.local文件中追加启动命令,该文件追加后,会随着机器自动后,自动运行文件中的命令 # vim /etc/rc.d/rc.local # 权限问题:在cent ...
- 游戏设计模式——C++单例类
前言: 本文将探讨单例类设计模式,单例类的懒汉模式/饿汉模式,单例类的多线程安全性,最后将利用C++模板减少单例类代码量. 本文假设有一个Manager管理类,并以此为探究单例类的设计模式. 懒汉模式 ...
- canopy聚类算法的MATLAB程序
canopy聚类算法的MATLAB程序 凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 1. canopy聚类算法简介 Canopy聚类算法是一个将对象分组到 ...
- nm U -l库的
nm U -l库的
- Maven更改本地默认仓库时遇到的问题。 No implementation for org.apache.maven.model.path.PathTranslator was bound
按照提示去查看log日志 2019-10-22 16:52:08,646 [ 161168] ERROR - #org.jetbrains.idea.maven - com.google. ...