C# 编写 windows 服务 采用多线对数据库操作

如图 写了一个windows服务安装在本机中,使服务能在我看不见的地方对数据库进行悄悄的修改。

你可以在网上搜索如何创建及安装一个windows服务,会搜索出来一大堆对你有帮助的东西,我就简单的说一下吧。

我电脑win7旗舰版,用的vs2010(经过上篇博文所说的过程,我是真心不行弄单位的电脑了) 和SQL Server 2008

创建无非就是在新建中找到windows☞windows服务☞命名及保存路径

我是在后台手敲了一个timer,你也可以在像如下所说的

在安装时只要在设计页右键☞添加安装程序,会自动出现

修改serviceInstaller1的Automatic属性为Automatic,ServiceName属性自定义个名称;

修改serviceProcessInsertaller1的LocalSystem属性为LocalSystem;

对着你的服务右键生成,然后在你的电脑中找到你服务的存储位置☞服务名称的文件夹☞bin☞Debug☞添加两个txt文件,分别命名为安装服务和卸载服务,内容分别为

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe  名称.exe
   pause       和

C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u 名称.exe
   pause

然后将两个.txt文件的后缀名称改为.bat ,安装时直接双击安装文件就行(懒人都这么干),卸载也一样。

我得服务叫Service1(我知道我很懒~~嘻嘻),在Service1.Designer.cs中定义了个时间控件

 private System.Timers.Timer timer1;

        private void InitializeComponent()
        {
            this.timer1 = new System.Timers.Timer();
            components = new System.ComponentModel.Container();
            this.ServiceName = "Service1";
            ((System.ComponentModel.ISupportInitialize)(this.timer1)).BeginInit();
            // 
            // timer1(毫秒数)
            // 300000    五分钟
            // 3600000   一小时
            // 86400000  一天
            this.timer1.Interval = 300000;
            this.timer1.Elapsed +=
          new System.Timers.ElapsedEventHandler(this.timer1_Elapsed);
            ((System.ComponentModel.ISupportInitialize)(this.timer1)).EndInit();
            //缺少这句会是服务不可启动哦,似乎报错说服务缺少依赖什么的
        }

并且将InitializeComponent()方法完善。
下列是Service1服务的基础操作代码

DataTable datatable = new DataTable();
        private Object rLock = new Object();//
        int nCurRowIndex = 0; //全局变量
        int times = 0;        //对数据库操作的次数

        public Service1()
        {
            InitializeComponent();
            InitService();
        }
        /// <summary>
        /// 初始化服务参数
        /// </summary>
        private void InitService()
        {
            base.AutoLog = false;
            base.CanShutdown = true;
            base.CanStop = true;
            base.CanPauseAndContinue = true;
            base.ServiceName = "Service1";  //这个名字很重要,设置不一致会产生 1083 错误哦!
        }
        /// <summary>
        /// 服务开始
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true))
            {
                sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "Start.");
            }
            this.timer1.Enabled = true;
        }
        /// <summary>
        /// 服务结束
        /// </summary>
        protected override void OnStop()
        {
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true))
            {
                sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "Stop.");
            }
            this.timer1.Enabled = false;
        }
        /// <summary>
        /// 服务暂停
        /// </summary>
        protected override void OnPause()
        {
            //服务暂停执行代码
            base.OnPause();
        }
        protected override void OnContinue()
        {
            //服务恢复执行代码
            base.OnContinue();
        }
        protected override void OnShutdown()
        {
            //系统即将关闭执行代码
            base.OnShutdown();
        }

        private void Elapsed()
        {
            GetAllWikipedia();
        }
        private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            //执行SQL语句或其他操作
            GetAllWikipedia();//达到时间走这个
        }

对于数据的查询很简单,就像是普通.net程序操作数据库一样

        /// <summary>
        /// 查询表
        /// </summary>
        /// <returns></returns>
        public DataTable ChaXun()
        {
            SqlConnection con = new SqlConnection("Data Source=. ;Initial Catalog=HDQYMS;Persist Security Info=True;User ID=sa;Password=sasa");
            string sql = "select * from Wikipedia";
            using (SqlCommand cmd = new SqlCommand(sql, con))
            {
                DataSet ds = new DataSet();
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                da.Fill(ds);
                con.Close();
                DataTable dt = ds.Tables[0];
                times++;
                using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true))
                {
                    sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "" + times + "次获取数据库中Wikipedia表");
                }
                return dt;
            }
        }

此处开启了两个线程来工作

 //这个是线程函数
        private void DoProcess()
        {
            bool flag = true;
            while (flag)
            {
                Thread nonParameterThreadA = new Thread(new ThreadStart(NonParameterRun));//创建线程
                nonParameterThreadA.Name = "ThreadA";
                nonParameterThreadA.Start();
                Thread nonParameterThreadB = new Thread(new ThreadStart(NonParameterRun));
                nonParameterThreadB.Name = "ThreadB";
                nonParameterThreadB.Start();
                flag = false;
            }
        }
        /// <summary> 
        /// 不带参数的启动方法 
        /// </summary> 
        public void NonParameterRun()
        {
            while (true)
            {
                lock (rLock)//
                {
                    DataRow rRow = GetRowToProcess();//获取行
                    if (rRow == null)
                    {
                        Thread.Sleep(300000);
                        nCurRowIndex = 0;
                        break;
                    }
                    //这里处理rRow,
                    else
                    {
                        try
                        {
                            Update(rRow);//真正要进行的工作
                            Thread.Sleep(10);
                        }
                        catch (Exception ex)
                        {
                            using (System.IO.StreamWriter sw = new System.IO.StreamWriter("D:\\log.txt", true))
                            {
                                sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + "发生异常" + ex);
                            }
                            OnStop();
                        }
                    }
                }
            }
        }

如上图是我要对数据库进行操作的表。我得服务要达到的目的就是在开启以后没隔一段时间就要查询一下数据库中表的内容其中LinkAddress是网址,我要根据这个网址去网上查询网页的源码,然后看一下我得QutsideAddress1,2,3这三个外链是否还有效,有效时就标识√,无效标识×,就这样。

但是我不得不说再做的时候遇到了几个问题

①在没有给Thread.Sleep(300000);时我的线程开启了两个,他们就会将我需要的操作全部执行两遍,如果开启了三个,那么就是全部执行三遍 ̄□ ̄||

   解决办法目前先是让线程休眠吧,有时间再弄。(谁又好的办法,或者知道我哪里写错了一定要告诉我哈~感激不尽....)

②因为在对外链的判断结束之后还要有对数据的修改操作,本想用个事务或者其他的使他们共同完成,可是加了多线程之后这个似乎就不好实现,或者说我没有找到方法,此处没有贴出具体的操作代码。我还是用的很笨的方式修改,不提也罢。

③我感觉放上了线程之后工作的时间似乎没有什么太大的改善啊,好像还是需要依赖于网速的~而且不知道是不是我没有定义这两个线程的优先级的问题,B线程都是要比A线程执行的多,大概四五个B线程执行完之后会有一个A的影子~

④因为第一次做windows服务,调试还是很让我头疼的,百度说启动后在程序中找到调试☞附加到进程☞√显示所有用户的进程☞刷新☞找到你的服务☞附加 即可进行调试,但是我找到的我得服务全是灰色的啊,根本不可能附加进程啊,所以我还是采用了一个最笨的办法,就是写工作日志,那里出错找哪里,(妈妈再也不用担心我得学习 ̄□ ̄||)

原文地址:https://www.cnblogs.com/wningning/p/3056902.html