【原創】c#實現用SQL池(多線程),定時批量執行SQL語句

作者: 田志良  來源: 博客園  發布時間: 2010-09-12 09:16  閱讀: 2442 次  推薦: 0   原文鏈接   [收藏]  

  在實際項目開發中,業務邏輯層的處理速度往往很快,特別是在開發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執行線程

  總結有以下三種方法,具體請參見http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813928.html

  方法一:調用線程執行方法,在方法中實現死循環,每個循環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();
        }
    }
}

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()