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();
}
}
}