说明:这里限制了并发执行存储过程的最大个数,但并没有对并发线程数进行控制,与文章标题略有不符,但程序稍做改动即可控制并发线程数
需求及解决方案:
1、定时执行存储过程,如何判断执行时间已到,并且不能重复执行?
不能用等于号判断时间相等,这样不太可靠,我采用的办法是用大于号判断,并且执行过后在数据库中记录一下,防止重复执行
2、如何限制同时执行的存储过程的个数?
定义了一个静态变量,通过静态变量判断
代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Data; using System.Data.OracleClient; using System.Diagnostics; using System.IO; using System.ServiceProcess; using System.Text; using System.Threading; using System.Timers; using System.Xml; using DBUtil; using FQDService.DAL; using FQDService.Models; using FQDService.Utils; namespace FQDService { /// <summary> /// FQD服务 /// </summary> partial class FQDService : ServiceBase { #region 变量 /// <summary> /// 执行存储过程线程数锁 /// </summary> public static Object lockTreadCount = new Object(); /// <summary> /// 执行存储过程超时时间 /// </summary> public static int timeout = int.Parse(ConfigurationManager.AppSettings["Timeout"].Trim()) * 60 * 1000; /// <summary> /// 等待执行存储过程时间间隔 /// </summary> public static int interval = 60 * 1000; /// <summary> /// 执行存储过程最大数 /// </summary> public static int maxRunProcCount = int.Parse(ConfigurationManager.AppSettings["MaxRunProcCount"].Trim()) * 60 * 1000; /// <summary> /// 执行存储过程数 /// </summary> public static int runProcCount = 0; #endregion #region 构造函数 public FQDService() { InitializeComponent(); } #endregion #region 启动 protected override void OnStart(string[] args) { // TODO: 在此处添加代码以启动服务。 System.Timers.Timer timer = new System.Timers.Timer(60 * 1000); timer.Elapsed += new System.Timers.ElapsedEventHandler(RunProc); timer.Start(); } #endregion #region 结束 protected override void OnStop() { // TODO: 在此处添加代码以执行停止服务所需的关闭操作。 } #endregion #region 执行存储过程 /// <summary> /// 执行存储过程 /// </summary> public void RunProc(object sender, ElapsedEventArgs e) { try { //Random rnd = new Random(); List<RunTimeCfg> runTimeCfgList = RunTimeCfgDal.GetListAll(); foreach (RunTimeCfg runTimeCfg in runTimeCfgList) // 遍历Proc { #region 判断是否到执行时间 bool run = false; if (runTimeCfg.RunType == 1) //按天执行 { // 今天没有执行过并且执行时间已到 if (DateTime.Now.Day != RunTimeCfgDal.GetLastRunTime(runTimeCfg.ProcName)) { DateTime dtRunTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd ") + runTimeCfg.RunTimeList[0]); if (DateTime.Now >= dtRunTime) run = true; } } else if (runTimeCfg.RunType == 2) //按月执行 { foreach (string runTime in runTimeCfg.RunTimeList) { // 今天是配置的日期并且今天没有执行过并且执行时间已到 int day = int.Parse(runTime.Split(' ')[0]); if (DateTime.Now.Day != RunTimeCfgDal.GetLastRunTime(runTimeCfg.ProcName) && DateTime.Now.Day == day) { DateTime dtRunTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-") + runTime); if (DateTime.Now >= dtRunTime) run = true; } } } #endregion if (run) { #region 执行 RunTimeCfgDal.SaveLastRunTime(runTimeCfg.ProcName); //更新最后执行时间 bool finish = false; //存储过程是否执行完毕 Thread thread = null; thread = new Thread(new ParameterizedThreadStart(delegate(object obj) { #region 等待执行存储过程 lock (lockTreadCount) { while (runProcCount >= maxRunProcCount) { Thread.Sleep(interval); } runProcCount++; } #endregion #region 执行存储过程超时处理 Thread threadTimer = new Thread(new ParameterizedThreadStart(delegate(object obj2) { Thread.Sleep(timeout); if (finish == false) { FileLogger.WriteLog(string.Format("存储过程{0}执行超时", runTimeCfg.ProcName)); if (thread != null) { try { thread.Abort(); } catch (Exception ex) { FileLogger.WriteErrorLog(string.Format("存储过程{0}终止线程出错:{1}", runTimeCfg.ProcName, ex.Message)); } } } })); threadTimer.Start(); #endregion #region 为执行存储过程准备参数 OracleParameter[] oracleParams = new OracleParameter[2]; oracleParams[0] = new OracleParameter("runType", OracleType.Number); oracleParams[1] = new OracleParameter("cutTime", OracleType.DateTime); oracleParams[0].Value = 1; oracleParams[1].Value = DateTime.Now.Date; #endregion try { try { #region 执行存储过程 FileLogger.WriteLog(string.Format("开始执行存储过程{0}", runTimeCfg.ProcName)); //执行存储过程 OracleHelper.RunProcedure(runTimeCfg.ProcName, oracleParams); //模拟执行存储过程 //Thread.Sleep(rnd.Next(100, 1900)); FileLogger.WriteLog(string.Format("存储过程{0}执行成功", runTimeCfg.ProcName)); finish = true; #endregion } catch (Exception ex) { #region 执行存储过程失败日志 StringBuilder sbParams = new StringBuilder(); foreach (OracleParameter oracleParam in oracleParams) { sbParams.Append(string.Format("{0}:{1},", oracleParam.ParameterName, oracleParam.Value.ToString())); } string strParams = ""; if (sbParams.Length > 0) strParams = sbParams.ToString(0, sbParams.Length - 1); FileLogger.WriteErrorLog(string.Format("存储过程执行失败{0}({1}):{2}", runTimeCfg.ProcName, strParams, ex.Message)); #endregion } } catch { //捕获线程终止异常 } finally { runProcCount--; } })); thread.Start(); #endregion } } } catch (Exception ex) { FileLogger.WriteErrorLog(ex.Message); } } #endregion } }