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

来源:互联网 发布:painter软件怎么样 编辑:程序博客网 时间:2024/05/29 17:41
在实际项目开发中,业务逻辑层的处理速度往往很快,特别是在开发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池代码:

 

view source
print?
01usingSystem;
02usingSystem.Collections.Generic;
03usingSystem.Linq;
04usingSystem.Text;
05usingSystem.Threading;
06  
07namespaceTest1
08{
09    sealedclassSQLPool
10    {
11        //互斥锁
12        publicstaticMutex mutexSQLPool =newMutex();
13  
14        //SQL池
15        Stack<string> pool;
16  
17        /// <summary>
18        /// 初始化SQL池
19        /// </summary>
20        internalSQLPool()
21        {
22            this.pool =newStack<string>();
23        }
24  
25  
26        /// <summary>
27        /// 获取SQL池数量
28        /// </summary>
29        internalInt32 Count
30        {
31            get{returnthis.pool.Count; }
32        }
33  
34  
35        /// <summary>
36        /// 从池中取出SQL
37        /// </summary>
38        /// <returns></returns>
39        internalstringPop()
40        {
41            lock(this.pool)
42            {
43                returnthis.pool.Pop();
44            }
45        }
46  
47  
48        /// <summary>
49        /// 增加一个SQL到池中
50        /// </summary>
51        /// <param name="item"></param>
52        internalvoidPush(stringitem)
53        {
54            if(item.Trim() =="")
55            {
56                thrownewArgumentNullException("Items added to a SQLPool cannot be null");
57            }
58  
59            //此处向SQL池中push SQL必须与Clear互斥
60            mutexSQLPool.WaitOne();
61            try
62            {
63                this.pool.Push(item);   //此处如果出错,则不会执行ReleaseMutex,将会死锁
64            }
65            catch
66            
67            }
68            mutexSQLPool.ReleaseMutex();
69        }
70  
71  
72        /// <summary>
73        /// 清空SQL池
74        /// 清空前,返回SQL池中所有SQL语句,
75        /// </summary>
76        internalstring[] Clear()
77        {
78            string[] array =newstring[] { };
79  
80            //此处必须与Push互斥
81            mutexSQLPool.WaitOne();
82            try
83            {
84                array =this.pool.ToArray();    //此处如果出错,则不会执行ReleaseMutex,将会死锁
85                this.pool.Clear();
86            }
87            catch
88            
89            }
90            mutexSQLPool.ReleaseMutex();
91  
92            returnarray;
93        }
94    }
95}

 

(二)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池管理类代码:

 

view source
print?
01usingSystem;
02usingSystem.Collections.Generic;
03usingSystem.Linq;
04usingSystem.Text;
05  
06namespaceTest1
07{
08    classSQLPoolManage
09    {
10        //单例模型
11        publicstaticreadonlySQLPoolManage sqlPoolManage =newSQLPoolManage();
12  
13        #region 属性
14        SQLPool poolOfSQL;
15        #endregion
16  
17  
18        #region 构造函数
19        /// <summary>
20        /// 初始化
21        /// </summary>
22        publicSQLPoolManage()
23        {
24            this.poolOfSQL =newSQLPool();
25        }
26        #endregion
27  
28  
29        #region 方法
30        /// <summary>
31        /// 将SQL语句加入SQL池中
32        /// </summary>
33        /// <param name="strSQL"></param>
34        publicvoidPushSQL(stringstrSQL)
35        {
36            this.poolOfSQL.Push(strSQL);
37        }
38  
39  
40        /// <summary>
41        /// 每隔一段时间,触发ExecuteSQL
42        /// ExecuteSQL用于执行SQL池中的SQL语句
43        /// </summary>
44        /// <param name="obj"></param>
45        publicvoidExecuteSQL(objectobj)
46        {
47            if(this.poolOfSQL.Count > 0)
48            {
49                string[] array =this.poolOfSQL.Clear();
50                //遍历array,执行SQL
51                for(inti = 0; i < array.Length; i++)
52                {
53                    if(array[i].ToString().Trim() !="")
54                    {
55                        try
56                        {
57                            //数据库操作
58                            //......
59                        }
60                        catch
61                        
62                        }
63                    }
64                }
65            }
66        }
67        #endregion
68  
69    }
70}

 

 

(三)定时触发SQL执行线程

  总结有以下三种方法,具体请参见http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813928.html:

方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间;

方法二:使用System.Timers.Timer类;

方法三:使用System.Threading.Timer;

  代码如下:

 

view source
print?
01usingSystem;
02usingSystem.Collections.Generic;
03usingSystem.Linq;
04usingSystem.Text;
05  
06usingSystem.Threading;
07  
08namespaceTest1
09{
10  
11    classProgram
12    {
13        staticvoidMain(string[] args)
14        {
15            //向SQL池中抛入SQL语句
16            SQLPoolManage.sqlPoolManage.PushSQL("delete from tbl_test where id = 1");
17  
18            //定时触发SQL执行线程
19            System.Threading.Timer threadTimer =newSystem.Threading.Timer(newSystem.Threading.TimerCallback(SQLPoolManage.sqlPoolManage.ExecuteSQL),null, 0, 100);
20  
21            Console.ReadLine();
22        }
23    }
24}