震驚!Windows Service服務和定時任務框架quartz之間原來是這種關係……

来源:https://www.cnblogs.com/xiongze520/archive/2020/06/03/13031944.html
-Advertisement-
Play Games

過場CG: 接到公司領導的文件指示,“小熊”需要在6月底去海外執行一個行動代號為【定時任務】的營救計劃,這個計劃關係到公司某個項目的生死(數據安全漏洞),作戰部擬定兩個作戰方案: 方案一:使用務定時任務框架quartz; 方案二:使用windows Service服務。 最終的作戰方案為:兩者配套使 ...


過場CG:   接到公司領導的文件指示,“小熊”需要在6月底去海外執行一個行動代號為【定時任務】的營救計劃,這個計劃關係到公司某個項目的生死(數據安全漏洞),作戰部擬定兩個作戰方案:   方案一:使用務定時任務框架quartz;   方案二:使用windows Service服務。   最終的作戰方案為:兩者配套使用。

  前言:項目開發完成後,對接的項目有很多個模塊,由於其中的一個環節疏忽,現在需要在原有的基礎上把缺失的數據自動寫入資料庫存儲起來。 重新修改程式邏輯已然不現實,現在需要一個補丁來進行邏輯更正。 補丁邏輯:兩個入口控制,
  • 入口一:點擊【更新】按鈕同步邏輯後的數據;
  • 入口二:每天晚上18:00進行執行同步邏輯後的數據;

  現在我們先使用window服務進行入口二的編寫(入口一隻需要一個按鈕調用入口二的邏輯即可) windows服務

一、開發環境

操作系統:Windows 7 X64/32

開發環境:VS2017

編程語言:C#

.NET版本:.NET Framework 4.6.1

二、創建Windows Service

1、新建一個Windows Service,並將項目名稱改為“MyWindowsService”,如下圖所示:

 

 2、在解決方案資源管理器內將Service1.cs改為MyWindowsService.cs後併在左邊頁面空白處點擊滑鼠右鍵,添加安裝程式,如下圖所示:

 

添加安裝程式:

 

 

3、 此時軟體會生成兩個組件,分別為“serviceInstaller1”及“serviceProcessInstaller1”,點擊“serviceInstaller1”,右鍵--->屬性,

將ServiceName改為MyWindowsService,Description改為“我的服務”,如下圖:

 

 

 4、點擊“serviceProcessInstaller1”,在“屬性”窗體將Account改為LocalSystem(服務屬性系統級別),如下圖所示:

     5、點擊MyWindowsService.cs,在左邊空白位置右鍵,“查看代碼”,然後編寫代碼,代碼我編寫好了,直接拷貝即可使用  
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MyWindowsService
{
    public partial class MyWindowsService : ServiceBase
    {
        public MyWindowsService()
        {
            InitializeComponent();
        }

        //創建進程
        public static Thread threadStartConfirmActualTime;  //創建一個時間進程
        public static Thread threadDoCheck;                 //檢查日誌時間進程

        //開啟服務
        protected override void OnStart(string[] args)
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t服務啟動!\n");
            StartServer();
        }

        //停止服務
        protected override void OnStop()
        {
            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t服務停止!\n");
        }

        //啟動服務操作
        private void StartServer()
        {
            try
            {
                threadStartConfirmActualTime = new Thread(new ThreadStart(new SingleClass().BeginConfirmMessageTime));//在進程下麵創建線程
                threadStartConfirmActualTime.Start();
                threadDoCheck.Start();
            }
            catch (Exception ex)
            {
                threadStartConfirmActualTime.Abort();//關閉線程
                Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t服務停止!"+ex.Message+"\n");
            }
        }


        /// <summary>
        /// Aouth:xiongze
        /// Time:2020/06/02
        /// Details:單例模式_建立一個單例類,保證只有一個對象被實例化,然後開啟服務
        /// </summary>
        public class SingleClass  //單例模式_建立一個單例類,保證只有一個對象被實例化
        {
            public static SingleClass _SingleClass;
            public static object onlock = new object();  //實例化一個鎖

            public static SingleClass Singleton
            {
                get
                {
                    if (_SingleClass == null)
                    {
                        lock (onlock)
                        {
                            _SingleClass = new SingleClass();
                        }
                    }
                    return _SingleClass;
                }
            }
            public void BeginConfirmMessageTime()  //開啟服務
            {
                while (true)
                {
                    //每天晚上18這一個小時內檢測執行
                    if (DateTime.Now.Hour.ToString("18") == "18")
                    {
                        try
                        {
                            //同步數據
                            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "我在"+ DateTime.Now + "同步了數據哦!\n");
                        }
                        catch (Exception ex)
                        {
                            //記錄錯誤日誌(記錄到相應的文件下麵)
                            Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "\t我是錯誤日誌!" + ex.Message + "\n");
                        }
                    }
                    Thread.Sleep(1800000);  //半個小時執行一次,註意,1000毫秒=1秒,具體需要多少時間可以自由換算 1800000半小時
                }

            }
        }

    }
}
  6、至此,Windows服務已經創建完畢。    三、創建安裝、啟動、停止、卸載服務的Windows窗體   1、點擊項目,右鍵,重新生成 在桌面上創建一個文件夾,命名為“我的服務”,將MyWindowsService項目項目生成的bin文件夾Debug文件夾的內容全部複製到新建的文件夾裡面; 然後去百度拷貝三個文件到“我的服務”文件裡面,分別為Install.bat(安裝)、UnInstall.bat(卸載)、InstallUtil.exe(執行), 打開文件,分別打開Install.bat和UnInstall.bat文件,將後面一個xxx.exe修改為你的文件程式,我們的是MyWindowsService.exe。如下圖

 

 

 

 

操作完後雙擊Install.bat進行安裝windows服務,安裝成功後點擊【電腦】-->右鍵-->管理-->服務裡面找到“我的服務”,啟動服務並修改為自動啟動;如下圖:  

 

 

 

 

 這樣就實現了windows服務入口二每天晚上18:00進行執行同步邏輯後的數據,只要代碼不報錯就一直執行;   優點:每天指定時間自動執行指定邏輯 缺點:程式在每次設置的時間內無限執行,消耗資源(CPU等)    
 quartz定時任務
 

一、開發環境

操作系統:Windows 7 X64

開發環境:VS2017

編程語言:C#

.NET版本:.NET Framework 4.6.1

二、創建quartz定時任務 1、創建一個控制台任務程式進行演示,命名為MyQuartz,創建如下:  

 

 2、引入quartz框架動態鏈接庫

在NuGet管理裡面搜索quartz進行安裝,註意:Quartz高版本的存在相容性,建議使用低版本的(2.5.0) 如下圖:  

 

 

3、創建一個執行的類,用於執行後臺數據邏輯,命名為TestJob,並且繼承Quartz框架的IJob介面,這個累的內容如下,可以直接拷貝
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyQuartz
{
    public class TestJob: IJob
    {
        public void Execute(IJobExecutionContext context)//指定調用的方法
        {
            try
            {
                //在這裡寫代碼(寫自己的業務邏輯)
                Console.WriteLine("任務執行啦" + DateTime.Now);
            }
            catch (Exception ex)
            {
                Console.WriteLine("定時任務出錯" + ex.Message);
            }
        }
    }
}

4、在Program.cs文件裡面進行調用編寫,編寫內容主要如下:

  1. 創建一個作業調度池;
  2. 創建出來一個具體的作業;
  3. 創建並配置一個觸發器;
  4. 加入作業調度池中;
  5. 開始運行。
 首先我們看完成代碼,然後進行講解(代碼可以直接拷貝):
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyQuartz
{
    class Program
    {
        static void Main(string[] args)
        {
            //1.首先創建一個作業調度池
            ISchedulerFactory schedf = new StdSchedulerFactory();
            IScheduler sched = schedf.GetScheduler();
            //2.創建出來一個具體的作業
            IJobDetail job = JobBuilder.Create<TestJob>().Build();
            //3.創建並配置一個觸發器

            #region(使用SimpleTrigger觸發器,每次3秒執行一次,無上限)
            ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().WithSimpleSchedule(x => x.WithIntervalInSeconds(3).WithRepeatCount(int.MaxValue)).Build();
            #endregion

            #region 每3秒執行一次 總共5次 ,開始執行時間設定在當前時間,結束時間我設定在2小時後,不過5次執行完沒2小時候都不再執行。
            //-------NextGivenSecondDate:如果第一個參數為null則表名當前時間往後推遲2秒的時間點。
            //DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(5), 2);
            //DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddHours(2), 3);
            //ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime)
            //                            .WithSimpleSchedule(x => x.WithIntervalInSeconds(3).WithRepeatCount(5))
            //                            .Build();
            #endregion

            #region (使用CronTrigger觸發器)在每小時的第10,20,25,26,33,54分鐘,每分鐘的第1,10,14秒執行一次
            //DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddSeconds(1), 2);
            //DateTimeOffset endTime = DateBuilder.NextGivenSecondDate(DateTime.Now.AddYears(2), 3);
            //ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create().StartAt(startTime).EndAt(endTime)
            //                            .WithCronSchedule("1,10,59 10,20,21,26,33,54 * * * ? ")
            //                            .Build();
            #endregion
            //4.加入作業調度池中
            sched.ScheduleJob(job, trigger);
            //5.開始運行
            sched.Start();
            Console.ReadKey();

        }
    }
}

 

在上面代碼中可以看出,我們主要使用了兩個觸發器:SimpleTrigger觸發器和CronTrigger觸發器;

SimpleTrigger觸發器(簡單觸發器SimpleTrigger)

SimpleTrigger可以滿足的調度需求是:在具體的時間點執行一次,或者在具體的時間點執行,並且以指定的間隔重覆執行若幹次。比如,你有一個trigger,你可以設置它在2015年1月13日的上午11:23:54準時觸發,或者在這個時間點觸發,並且每隔2秒觸發一次,一共重覆5次。

根據描述,你可能已經發現了,SimpleTrigger的屬性包括:開始時間、結束時間、重覆次數以及重覆的間隔。這些屬性的含義與你所期望的是一致的,只是關於結束時間有一些地方需要註意。

重覆次數,可以是0、正整數,以及常量SimpleTrigger.REPEAT_INDEFINITELY。重覆的間隔,必須是0,或者long型的正數,表示毫秒。註意,如果重覆間隔為0,trigger將會以重覆次數併發執行(或者以scheduler可以處理的近似併發數)。

如果你還不熟悉DateBuilder,瞭解後你會發現使用它可以非常方便地構造基於開始時間(或終止時間)的調度策略。

endTime屬性的值會覆蓋設置重覆次數的屬性值;比如,你可以創建一個trigger,在終止時間之前每隔10秒執行一次,你不需要去計算在開始時間和終止時間之間的重覆次數,只需要設置終止時間並將重覆次數設置為REPEAT_INDEFINITELY(當然,你也可以將重覆次數設置為一個很大的值,並保證該值比trigger在終止時間之前實際觸發的次數要大即可)。

 

具體用法我們就不水文了,大家去看Quartz官網文檔的用法即可SimpleTrigger觸發器使用規則:https://www.w3cschool.cn/quartz_doc/quartz_doc-67a52d1f.html,部分截圖顯示如下:
  • 指定時間開始觸發,不重覆:
  • 指定時間觸發,每隔10秒執行一次,重覆10次:
  • 5分鐘以後開始觸發,僅執行一次:
  • 立即觸發,每個5分鐘執行一次,直到22:00:
  • 建立一個觸發器,將在下一個小時的整點觸發,然後每2小時重覆一次:

 

 

CronTriggerr觸發器(基於Cron表達式的觸發器CronTriggerr

CronTrigger通常比Simple Trigger更有用,如果您需要基於日曆的概念而不是按照SimpleTrigger的精確指定間隔進行重新啟動的作業啟動計劃。

使用CronTrigger,您可以指定號時間表,例如“每周五中午”或“每個工作日和上午9:30”,甚至“每周一至周五上午9:00至10點之間每5分鐘”和1月份的星期五“。

即使如此,和SimpleTrigger一樣,CronTrigger有一個startTime,它指定何時生效,以及一個(可選的)endTime,用於指定何時停止計劃。

Cron Expressions
Cron-Expressions用於配置CronTrigger的實例。Cron Expressions是由七個子表達式組成的字元串,用於描述日程表的各個細節。這些子表達式用空格分隔,並表示:

Seconds
Minutes
Hours
Day-of-Month
Month
Day-of-Week
Year (optional field)
一個完整的Cron-Expressions的例子是字元串“0 0 12?* WED“ - 這意味著”每個星期三下午12:00“。
單個子表達式可以包含範圍和/或列表。例如,可以用“MON-FRI”,“MON,WED,FRI”或甚至“MON-WED,SAT”代替前一個(例如“WED”)示例中的星期幾欄位。
通配符(' '字元)可用於說明該欄位的“每個”可能的值。因此,前一個例子的“月”欄位中的“”字元僅僅是“每個月”。因此,“星期幾”欄位中的“*”顯然意味著“每周的每一天”。
所有欄位都有一組可以指定的有效值。這些值應該是相當明顯的 - 例如秒和分鐘的數字0到59,數小時的值0到23。日期可以是1-31的任何值,但是您需要註意在給定的月份中有多少天!月份可以指定為0到11之間的值,或者使用字元串JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC。星期幾可以指定為1到7(1 =星期日)之間的值,或者使用字元串SUN,MON,TUE,WED,THU,FRI和SAT。
'/'字元可用於指定值的增量。例如,如果在“分鐘”欄位中輸入“0/15”,則表示“每隔15分鐘,從零開始”。如果您在“分鐘”欄位中使用“3/20”,則意味著“每隔20分鐘,從三分鐘開始” - 換句話說,它與“分鐘”中的“3,243,43”相同領域。請註意“ / 35”的細微之處並不代表“每35分鐘” - 這意味著“每隔35分鐘,從零開始” - 或者換句話說,與指定“0,35”相同。
'' 字元是允許的日期和星期幾欄位。用於指定“無特定值”。當您需要在兩個欄位中的一個欄位中指定某個字元而不是另一個欄位時,這很有用。請參閱下麵的示例(和CronTrigger JavaDoc)以進行說明。
“L”字元允許用於月日和星期幾欄位。這個角色對於“最後”來說是短暫的,但是在這兩個領域的每一個領域都有不同的含義。例如,“月”欄位中的“L”表示“月的最後一天” - 1月31日,非閏年2月28日。如果在本周的某一天使用,它只是意味著“7”或“SAT”。但是如果在星期幾的領域中再次使用這個值,就意味著“最後一個月的xxx日”,例如“6L”或“FRIL”都意味著“月的最後一個星期五”。您還可以指定從該月最後一天的偏移量,例如“L-3”,這意味著日曆月份的第三個到最後一天。當使用'L'選項時,重要的是不要指定列表或值的範圍,因為您會得到混亂/意外的結果。
“W”用於指定最近給定日期的工作日(星期一至星期五)。例如,如果要將“15W”指定為月日期欄位的值,則意思是:“最近的平日到當月15日”。
''用於指定本月的“第n個”XXX工作日。例如,“星期幾”欄位中的“63”或“FRI#3”的值表示“本月的第三個星期五”。
以下是一些表達式及其含義的更多示例 - 您可以在JavaDoc中找到更多的org.quartz.CronExpression

Cron Expressions示例
CronTrigger示例1 - 創建一個觸發器的表達式,每5分鐘就會觸發一次
“0 0/5 * * *?”

CronTrigger示例2 - 創建觸發器的表達式,每5分鐘觸發一次,分鐘後10秒(即上午10時10分,上午10:05:10等)。
“10 0/5 * * *?”

CronTrigger示例3 - 在每個星期三和星期五的10:3011:3012:30和13:30創建觸發器的表達式。
“0 30 10-13?* WED,FRI“

CronTrigger示例4 - 創建觸發器的表達式,每個月5日和20日上午8點至10點之間每半小時觸發一次。請註意,觸發器將不會在上午10點開始,僅在8:008:309:00和9:300 0/30 8-9 5,20 *?”

請註意,一些調度要求太複雜,無法用單一觸發表示 - 例如“每上午9:00至10:00之間每5分鐘,下午1:00至晚上10點之間每20分鐘”一次。在這種情況下的解決方案是簡單地創建兩個觸發器,並註冊它們來運行相同的作業。

 

具體使用方法見CronTrigger觸發器使用規則https://www.w3cschool.cn/quartz_doc/quartz_doc-lwuv2d2a.html

  • 建立一個觸發器,每隔一分鐘,每天上午8點至下午5點之間:
  • 建立一個觸發器,將在上午10:42每天發射:
  • 建立一個觸發器,將在星期三上午10:42在TimeZone(系統預設值)之外觸發:

 

 

 


執行演示

寫完後我們查看執行結果,我使用的是SimpleTrigger觸發器,每3秒執行一次,無上限,各位可以根據自身的項目需求更改使用不同的觸發器

 

 

註意:

如果定時任務框架quartz這個掛在iis上會被回收掉(預設是20分鐘)

Quartz高版本的存在相容性,建議使用低版本的(2.5.0)

 


 

總結

到這裡Windows Service服務和定時任務框架quartz都簡單的介紹完了,具體使用哪一個或者配套使用就看本身項目邏輯了;

現在執行的邏輯:

Windows Service服務:程式隨電腦開機啟動,每隔半個小時執行一次,檢測到執行時間等於我設置的時間就去執行後臺邏輯;

定時任務框架quartz:如果發佈在iis上,預設20分鐘後會被回收(程式不能一直等待執行),程式處於休眠狀態,到指定時候後喚醒(觸發器)程式執行後臺邏輯;

 

PS:如果把quartz結合windows服務使用的話就不存在被回收問題;

 
歡迎關註訂閱我的微信公眾平臺【熊澤有話說】,更多好玩易學知識等你來取
作者:熊澤-學習中的苦與樂
公眾號:熊澤有話說
出處: https://www.cnblogs.com/xiongze520/p/13031944.html
創作不易,任何人或團體、機構全部轉載或者部分轉載、摘錄,請在文章明顯位置註明作者和原文鏈接。  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 什麼是sam 轉換 Single Abstract Method 實際上這是java8中提出的概念,你就把他理解為是一個方法的介面的就可以了 看一下我們每天都在使用的線程池 ExecutorService executorService= Executors.newScheduledThreadPo ...
  • 結合 AOP 輕鬆處理事件發佈處理日誌 Intro 前段時間,實現了 EventBus 以及 EventQueue 基於 Event 的事件處理,但是沒有做日誌(EventLog)相關的部分,原本想增加兩個介面, 處理事件發佈日誌和事件處理日誌,最近用了 AOP 的思想處理了 EntityFrame ...
  • Microsoft.AspNetCore.Mvc.Versioning //引入程式集 .net core 下麵api的版本控製作用不需要多說,可以查閱https://www.cnblogs.com/dc20181010/p/11313738.html 普通的版本控制一般是通過鏈接、header此類 ...
  • 系列文章 基於 abp vNext 和 .NET Core 開發博客項目 - 使用 abp cli 搭建項目 基於 abp vNext 和 .NET Core 開發博客項目 - 給項目瘦身,讓它跑起來 基於 abp vNext 和 .NET Core 開發博客項目 - 完善與美化,Swagger登場 ...
  • 引用NModbus 在NuGet搜索NModbus,添加引用。 封裝ModbusTcp類 public class ModbusTCP { private ModbusFactory modbusFactory; private IModbusMaster master; private TcpCl ...
  • 參考文檔: https://www.cnblogs.com/liaods/p/10101513.html https://www.cnblogs.com/zyz-Notes/p/12030281.html 本示例使用MVC項目做演示(不推薦,推薦直接用WebAPI),框架版本使用 4.6.2 為了支 ...
  • 前幾天,公眾號後臺有朋友在問Core的中間件,所以專門抽時間整理了這樣一篇文章。 一、前言 中間件(Middleware)最初是一個機械上的概念,說的是兩個不同的運動結構中間的連接件。後來這個概念延伸到軟體行業,大家把應用操作系統和電腦硬體之間過渡的軟體或系統稱之為中間件,比方驅動程式,就是一個典型 ...
  • 為什麼編寫TaskSchedulerEx類? 因為.NET預設線程池只有一個線程池,如果某個批量任務一直占著大量線程,甚至耗盡預設線程池,則會嚴重影響應用程式域中其它任務或批量任務的性能。 特點: 1、使用獨立線程池,線程池中線程分為核心線程和輔助線程,輔助線程會動態增加和釋放,且匯流排程數不大於參數 ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...