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池代码:
01 |
using
System; |
02 |
using
System.Collections.Generic; |
03 |
using
System.Linq; |
04 |
using
System.Text; |
05 |
using
System.Threading; |
06 |
|
07 |
namespace
Test1 |
08 |
{ |
09 |
sealed
class SQLPool
|
10 |
{
|
11 |
//互斥锁
|
12 |
public
static Mutex mutexSQLPool =
new Mutex();
|
13 |
|
14 |
//SQL池
|
15 |
Stack< string > pool;
|
16 |
|
17 |
/// <summary>
|
18 |
/// 初始化SQL池
|
19 |
/// </summary>
|
20 |
internal
SQLPool() |
21 |
{
|
22 |
this .pool =
new Stack< string >();
|
23 |
}
|
24 |
|
25 |
|
26 |
/// <summary>
|
27 |
/// 获取SQL池数量
|
28 |
/// </summary>
|
29 |
internal
Int32 Count |
30 |
{
|
31 |
get
{ return
this .pool.Count; } |
32 |
}
|
33 |
|
34 |
|
35 |
/// <summary>
|
36 |
/// 从池中取出SQL
|
37 |
/// </summary>
|
38 |
/// <returns></returns>
|
39 |
internal
string Pop()
|
40 |
{
|
41 |
lock
( this .pool)
|
42 |
{
|
43 |
return
this .pool.Pop();
|
44 |
}
|
45 |
}
|
46 |
|
47 |
|
48 |
/// <summary>
|
49 |
/// 增加一个SQL到池中
|
50 |
/// </summary>
|
51 |
/// <param name="item"></param>
|
52 |
internal
void Push( string
item) |
53 |
{
|
54 |
if
(item.Trim() == "" )
|
55 |
{
|
56 |
throw
new ArgumentNullException( "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 |
internal
string [] Clear()
|
77 |
{
|
78 |
string [] array =
new string [] { };
|
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 |
return
array; |
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池管理类代码:
01 |
using
System; |
02 |
using
System.Collections.Generic; |
03 |
using
System.Linq; |
04 |
using
System.Text; |
05 |
|
06 |
namespace
Test1 |
07 |
{ |
08 |
class
SQLPoolManage |
09 |
{
|
10 |
//单例模型
|
11 |
public
static readonly
SQLPoolManage sqlPoolManage = new
SQLPoolManage(); |
12 |
|
13 |
#region 属性
|
14 |
SQLPool poolOfSQL;
|
15 |
#endregion
|
16 |
|
17 |
|
18 |
#region 构造函数
|
19 |
/// <summary>
|
20 |
/// 初始化
|
21 |
/// </summary>
|
22 |
public
SQLPoolManage() |
23 |
{
|
24 |
this .poolOfSQL =
new SQLPool();
|
25 |
}
|
26 |
#endregion
|
27 |
|
28 |
|
29 |
#region 方法
|
30 |
/// <summary>
|
31 |
/// 将SQL语句加入SQL池中
|
32 |
/// </summary>
|
33 |
/// <param name="strSQL"></param>
|
34 |
public
void PushSQL( string
strSQL) |
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 |
public
void ExecuteSQL( object
obj) |
46 |
{
|
47 |
if
( this .poolOfSQL.Count > 0)
|
48 |
{
|
49 |
string [] array =
this .poolOfSQL.Clear();
|
50 |
//遍历array,执行SQL
|
51 |
for
( int
i = 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;
代码如下:
01 |
using
System; |
02 |
using
System.Collections.Generic; |
03 |
using
System.Linq; |
04 |
using
System.Text; |
05 |
|
06 |
using
System.Threading; |
07 |
|
08 |
namespace
Test1 |
09 |
{ |
10 |
|
11 |
class
Program |
12 |
{
|
13 |
static
void Main( 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 =
new System.Threading.Timer( new
System.Threading.TimerCallback(SQLPoolManage.sqlPoolManage.ExecuteSQL),
null , 0, 100);
|
20 |
|
21 |
Console.ReadLine();
|
22 |
}
|
23 |
}
|
24 |
} |