首先说明一下:这个例子是来源于【C#线程参考手册】参考手册内的一个例子,在这个我只是想研究一下她的设计原理。
具体好用不好用,因为没有做具体项目的测试,所以提醒大家注意。
1 设计思路:
1.1 在程序的全局利用单例模式建立一个数据库连接池对象。
1.2 获得数据库连接方法BorrowDBConnection()。
这个方法的作用如下:
如果【待清理的池】内DB连接对象不是关闭状态,则添加到【DB连接池】,继续使用。
如果【待清理的池】内DB连接对象是关闭状态,则DB连接被移除【待清理的池】,之后被关闭。
如果【待清理的池】不存在DB连接对象,则创建DB连接对象后,附加到【DB连接池】内,然后使用她。
1.3 返回数据库连接给【待清理的池】,方法是ReturnObjectToPool()。
【DB连接池】删除DB连接对象。
【待清理的池】追加DB连接对象。
1.4 延迟DB连接对象的垃圾回收事件
通过Timer的Elapsed事件,来实现【待清理的池】内的DB连接对象的关闭处理。
2 UML图例:
这里要说明的是,为什么要继承ObjectPool类呢?
因为ObjectPool类的结构对于所有使用池、可手动释放资源的对象是通用的。
3 具体代码如下:
3.1 ObjectPool类(真的很通用的一个类,设计的很好,感觉可以继承她做任何事)
using System;
using System.Collections;
using System.Timers;
using System.Text;
namespace SqlPool
{
public abstract class ObjectPool
{
///
/// //当前日期时间刻度值,用户判断连接是否超时
///
private long _lastCheckOut;
///
/// 使用对象池
///
private static Hashtable locked;
///
/// 清理对象池
///
private static Hashtable unlocked;
internal static long GARBAGE_INTERVAL = 5 * 1000;
///
/// 构造函数1,说明了两个池是同步的。
///
static ObjectPool()
{
locked = Hashtable.Synchronized(new Hashtable());
unlocked = Hashtable.Synchronized(new Hashtable());
}
///
/// 初始化时间间隔,时间间隔触发事件,释放清理对象池的对象
///
internal ObjectPool()
{
_lastCheckOut = DateTime.Now.Ticks;
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Enabled = true;
aTimer.Interval = GARBAGE_INTERVAL;
aTimer.Elapsed += new ElapsedEventHandler(CollectGarbage);
}
///
/// 建立一个数据库连接
///
///
protected abstract object Create();
///
/// 判断数据库连接是否正常
///
///
///
protected abstract bool Validate(object o);
///
/// 延迟的连接被关闭
///
///
protected abstract void Expire(object o);
///
/// Sql连接超出指定时间后的垃圾回收
///
///
///
private void CollectGarbage(object sender, ElapsedEventArgs ea)
{
lock (this)
{
object o;
long now = DateTime.Now.Ticks;
IDictionaryEnumerator e = unlocked.GetEnumerator();
try {
while (e.MoveNext())
{
o = e.Key;
if(now-((long)unlocked[o])>GARBAGE_INTERVAL)
{
unlocked.Remove(o);
Expire(o);
o = null;
}
}
}
catch{}
}
}
///
/// 获得数据库连接
///
///
internal object GetObjectFromPool()
{
long now = DateTime.Now.Ticks;
_lastCheckOut = now;
object o = null;
lock (this)
{
try
{
foreach (DictionaryEntry myEntry in unlocked)
{
o = myEntry.Key;
if (Validate(o))
{
unlocked.Remove(o);
locked.Add(o, now);
return (o);
}
else
{
unlocked.Remove(o);
Expire(o);
o = null;
}
}
}
catch (Exception) { }
o = Create();
locked.Add(o, now);
}
return o;
}
///
/// 清除数据库连接
///
///
internal void ReturnObjectToPool(object o)
{
if (o != null)
{
lock (this)
{
locked.Remove(o);
unlocked.Add(o, DateTime.Now.Ticks);
}
}
}
}
}
3.2 DBConnectionSingleton类 - 数据库连接池(实现了ObjectPool类的Create,Validate,Expire方法,并使用了单例模式)
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
namespace SqlPool
{
class DBConnectionSingleton:ObjectPool
{
private DBConnectionSingleton() { }
///
/// 以单例模式创建数据库连接池
///
public static readonly DBConnectionSingleton Instance = new DBConnectionSingleton();
private static string _connectionString = @"Data Source=192.168.168.251/Sql2005;Initial Catalog=XX;User ID=sa;Password=777";
///
/// 数据库连接字符串
///
public static string ConnectionString
{
set {
_connectionString = value;
}
get
{
return _connectionString;
}
}
///
/// 创建数据库连接
///
///
protected override object Create()
{
SqlConnection temp = new SqlConnection(_connectionString);
temp.Open();
return temp;
}
///
/// 判断DB是否已连接
///
///
///
protected override bool Validate(object o)
{
try
{
SqlConnection temp = (SqlConnection)o;
return (!((temp.State.Equals(System.Data.ConnectionState.Closed))));
}
catch
{
return false;
}
}
///
/// 关闭DB连接
///
///
protected override void Expire(object o)
{
try
{
((SqlConnection)o).Close();
}
catch {
}
}
///
/// 获得DB连接
///
///
public SqlConnection BorrowDBConnection()
{
try
{
return ((SqlConnection)base.GetObjectFromPool());
}
catch(Exception e) {
throw e;
}
}
///
/// 清除DB连接
///
///
public void ReturnDBConnecion(SqlConnection e)
{
base.ReturnObjectToPool(e);
}
}
}
3.3 Main函数
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
namespace SqlPool
{
class Program
{
static void Main(string[] args)
{
DBConnectionSingleton pool;
//获得数据库连接池的单例模式。
pool = DBConnectionSingleton.Instance;
DBConnectionSingleton.ConnectionString = @"Data Source=192.168.168.251/Sql2005;Initial Catalog=XX;User ID=sa;Password=777";
SqlConnection myConnection = pool.BorrowDBConnection();
pool.ReturnDBConnecion(myConnection);
System.Threading.Thread.Sleep(5000);
}
}
}