天天看点

c#实现用SQL池,多线程定时批量执行SQL语句

在实际项目开发中,业务逻辑层的处理速度往往很快,特别是在开发Socket通信服务的时候,网络传输很快,但是一旦加上数据库操作,性能一落千丈,数据库操作的效率往往成为一个系统整体性能的瓶颈。面对这问题,我们怎么办呢?好,下面我就为大家介绍一种方法:构建SQL池,分离业务逻辑层和数据访问层,让业务逻辑层从低效的数据库操作解脱,以提高系统整体性能。
(一)SQL池
  SQL池是SQL容器,用于存放业务逻辑层抛过来的SQL语句。SQL池主要提供以下几种方法:
1)internal string Pop(),从池中取出SQL。
2)internal void Push(string item),增加一个SQL到池中。
3)internal string[] Clear(),清空SQL池,清空前,返回SQL池中所有SQL语句。
  特别提醒一下,SQL池是面向多线程的,所以必须对公共资源SQL采取锁机制。这里采用互斥锁,当业务逻辑层线程往SQL池中抛入SQL语句时,禁止SQL执行线程执行SQL语句,反之,当SQL执行线程执行SQL语句时,也不允许业务逻辑层线程往SQL池中抛入SQL语句。为什么要这么做?因为SQL执行线程是批量执行SQL语句,在批量执行SQL语句前,会从池中取出所有SQL语句,如果此时业务逻辑层线程往SQL池中抛入SQL语句,则会导致这些SQL语句丢失,得不到执行。
  下面是SQL池代码:
using System; 
 using System.Collections.Generic; 
 using System.Linq; 
 using System.Text; 
 using System.Threading; 
   
 namespace Test1 
 { 
     sealed class SQLPool 
     { 
         //互斥锁 
         public static Mutex mutexSQLPool = new Mutex(); 
   
         //SQL池 
         Stack<string> pool; 
   
         /// <summary> 
         /// 初始化SQL池 
         /// </summary> 
         internal SQLPool() 
         { 
             this.pool = new Stack<string>(); 
         } 
   
   
         /// <summary> 
         /// 获取SQL池数量 
         /// </summary> 
         internal Int32 Count 
         { 
             get { return this.pool.Count; } 
         } 
   
   
         /// <summary> 
         /// 从池中取出SQL 
         /// </summary> 
         /// <returns></returns> 
         internal string Pop() 
         { 
             lock (this.pool) 
             { 
                 return this.pool.Pop(); 
             } 
         } 
   
   
         /// <summary> 
         /// 增加一个SQL到池中 
         /// </summary> 
         /// <param name="item"></param> 
         internal void Push(string item) 
         { 
             if (item.Trim() == "") 
             { 
                 throw new ArgumentNullException("Items added to a SQLPool cannot be null");
             } 
   
             //此处向SQL池中push SQL必须与Clear互斥 
             mutexSQLPool.WaitOne(); 
             try
             { 
                 this.pool.Push(item);    //此处如果出错,则不会执行ReleaseMutex,将会死锁 
             } 
             catch
             {  
             } 
             mutexSQLPool.ReleaseMutex(); 
         } 
   
   
         /// <summary> 
         /// 清空SQL池 
         /// 清空前,返回SQL池中所有SQL语句, 
         /// </summary> 
         internal string[] Clear() 
         { 
             string[] array = new string[] { }; 
   
             //此处必须与Push互斥 
             mutexSQLPool.WaitOne(); 
             try
             { 
                 array = this.pool.ToArray();     //此处如果出错,则不会执行ReleaseMutex,将会死锁 
                 this.pool.Clear(); 
             } 
             catch
             {  
             } 
             mutexSQLPool.ReleaseMutex(); 
   
             return array; 
         } 
     } 
 } 
  (二)SQL池管理
  SQL池管理主要用于管理SQL池,向业务逻辑层线程和SQL执行线程提供接口。
  业务逻辑层线程调用 public void PushSQL(string strSQL) 方法,用于向SQL池抛入SQL语句。
  SQL执行线程调用 public void ExecuteSQL(object obj) 方法,用于批量执行SQL池中的SQL语句。
  注意,SQL池管理类采用单例模型,为什么要采用单例模型?因为SQL池只能存在一个实例,无论是业务逻辑层线程还是SQL执行线程,仅会操作这一个实例,否则,将会导致SQL池不唯一,SQL执行无效。
  下面是SQL池管理类代码:
using System; 
 using System.Collections.Generic; 
 using System.Linq; 
 using System.Text; 
   
 namespace Test1 
 { 
     class SQLPoolManage 
     { 
         //单例模型 
         public static readonly SQLPoolManage sqlPoolManage = new SQLPoolManage();
   
         #region 属性 
         SQLPool poolOfSQL; 
         #endregion 
   
   
         #region 构造函数 
         /// <summary> 
         /// 初始化 
         /// </summary> 
         public SQLPoolManage() 
         { 
             this.poolOfSQL = new SQLPool(); 
         } 
         #endregion 
   
   
         #region 方法 
         /// <summary> 
         /// 将SQL语句加入SQL池中 
         /// </summary> 
         /// <param name="strSQL"></param> 
         public void PushSQL(string strSQL) 
         { 
             this.poolOfSQL.Push(strSQL); 
         } 
   
   
         /// <summary> 
         /// 每隔一段时间,触发ExecuteSQL 
         /// ExecuteSQL用于执行SQL池中的SQL语句 
         /// </summary> 
         /// <param name="obj"></param> 
         public void ExecuteSQL(object obj) 
         { 
             if (this.poolOfSQL.Count > 0) 
             { 
                 string[] array = this.poolOfSQL.Clear(); 
                 //遍历array,执行SQL 
                 for (int i = 0; i < array.Length; i++) 
                 { 
                     if (array[i].ToString().Trim() != "") 
                     { 
                         try
                         { 
                             //数据库操作 
                             //...... 
                         } 
                         catch
                         {  
                         } 
                     } 
                 } 
             } 
         } 
         #endregion 
   
     } 
 } 
   
(三)定时触发SQL执行线程
  总结有以下三种方法
方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间;
方法二:使用System.Timers.Timer类;
方法三:使用System.Threading.Timer;
  代码如下:
 
using System; 
 using System.Collections.Generic; 
 using System.Linq; 
 using System.Text; 
   
 using System.Threading; 
   
 namespace Test1 
 { 
   
     class Program 
     { 
         static void Main(string[] args)
         { 
             //向SQL池中抛入SQL语句 
             SQLPoolManage.sqlPoolManage.PushSQL("delete from tbl_test where id = 1");
   
             //定时触发SQL执行线程 
             System.Threading.Timer threadTimer = new System.Threading.Timer(new System.Threading.TimerCallback(SQLPoolManage.sqlPoolManage.ExecuteSQL), null, 0, 100);
   
             Console.ReadLine(); 
         } 
     } 
 }