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& ...
随机推荐
- 来认识一下venus-init——一个让你仅需一个命令开始Java开发的命令行工具
源代码地址: Github仓库地址 个人网站:个人网站地址 前言 不知道你是否有过这样的经历.不管你是什么岗位,前端也好,后端也罢,想去了解一下Java开发到底是什么样的,它是不是真的跟传说中的一样. ...
- 数据库——SQL-SERVER练习(4) 建表及数据完整性
1. 输入下图的语句, 建立学生表STU. CREATE TABLE STU ( SNO NUMERIC() PRIMARY KEY, SNANE CHAR() NOT NULL, SSEX CHAR ...
- 同步IDEA系列软件的设置,再也不用但心我的配置丢失了
同步IDEA系列软件的设置 问题描述:重装idea,之前配置好的快捷键就没有了.之前一直是每隔几个月要把配置导出一下,上传百度云盘.现在好了,通过配置可以自动同步配置了.我再也不用但心配置丢失了. 快 ...
- oracle学习笔记(十六) PL/SQL 异常和goto语句
PL/SQL 异常和goto语句 异常 预定义异常 oracle常见预定义异常: 错误号 异常错误信息名称 说明 ORA-0001 DUP_VAL_ON_INDEX 试图破坏一个唯一性限制 ORA-0 ...
- Android studio移动项目到另外一个文件夹,结果不能安装的解决方法
删除.gradle , .idea , build 三个文件夹即可
- WPF自定义控件之图片控件 AsyncImage
AsyncImage 是一个封装完善,使用简便,功能齐全的WPF图片控件,比直接使用Image相对来说更加方便,但它的内部仍然使用Image承载图像,只不过在其基础上进行了一次完善成熟的封装 Asyn ...
- 高强度学习训练第十一天总结:Class文件结构(二)
常量池 可以理解为Class文件之中的资源仓库,他是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一 访问标志 在常量池结束后,紧接着的俩个字节代表访问标 ...
- .NET MVC后台获得VIEW对应的html
一..Net Core Mvc下获得 建立一个帮助类,如下: using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Render ...
- 微信小程序上拉加载——分页
wxml: <view class="page"> <scroll-view class="imageViewCss_1" scroll-y= ...
- Angular 学习笔记(一)
什么是 Angular: Angular 是一个 JavaScript 框架,可通过 <script> 标签添加到 HTML 页面,然后通过指令扩展 HTML,且通过表达式绑定数据到 HT ...