缓存
小弟最近在编写一个O/RM组件(当然功能还是相当少的)。
大家都应该清楚把实体对象更新到数据库必须经过一系列的转换;特别是SQL语句的生成是比较费资源的,因为中间处里的东西实大是太多了。
在设计的过程中我就想如果一个对象插入数据库后把相应的Command保存在缓存中;下一次同一个类型的对象做这个操作时检测一下缓存如果有就直接拿来用这样效率应该会高些。
抱着这种想法就开始设计了(不过心里还是上上下下的,毕竟第一次尝试)。
因为缓存中的对象处理比较复杂点,在多线程中存在共享的问题,如果两个线程同时调用同一个Command这样一定会产生处理错误的!
为了更好地控制Command对象的共享,特别为Command定义了持久化的接口。
经过一段时间的设计和编写,算有点成果吧,顺把自己做的东西共享一下。
以下是组件测试的情况
P4 2.4 1G
SqlServer sp3
运行的代码大概如下:
Entitys.Customers customer = new Test.Entitys.Customers();
DateTime dt = DateTime.Now;
using(HFSoft.Data.IDataSession session = mapcontainer.OpenSession())
{
session.Open();
for(int i =0;i<2000;i++)
{
customer.CustomerID = Guid.NewGuid().ToString();
customer.CompanyName = "henry";
session.Save(customer);
}
}
tp1 = new TimeSpan(DateTime.Now.Ticks - dt.Ticks);
不开启缓存(5个线程运行时间)
00:00:05.7031250
00:00:06.8281250
00:00:05.0156250
00:00:06.6875000
00:00:06.4218750
--------------------------------------------------------
开启5个命令缓存(5个线程运行时间)
00:00:04.8906250
00:00:03.5625000
00:00:02.8750000
00:00:04.9375000
00:00:05.4843750
---------------------------------------------------------
以下是缓存类的源码
/// <summary>
/// 数据缓存保存信息异步处理委托
/// </summary>
delegate void EventSaveCache(object key,object value);
/// <summary>
/// 对象缓存类
/// </summary>
public class Cache
{
private MappingContainer mContainer;
/// <summary>
/// 获取或设置当前缓存对象所在的关系映象容器
/// </summary>
public MappingContainer Container
{
get
{
return mContainer;
}
set
{
mContainer = value;
}
}
/// <summary>
/// 构造缓存对象
/// </summary>
public Cache()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
/// <summary>
/// 用于缓存数据的Hashtable
/// </summary>
protected System.Collections.Hashtable _Cache = new System.Collections.Hashtable();
protected Object _LockObj = new object();
/// <summary>
/// 获取指定键值的对象
/// </summary>
/// <param name="key">键值</param>
/// <returns>object</returns>
public virtual object GetObject(object key)
{
if(_Cache.ContainsKey(key))
return _Cache[key];
return null;
}
/// <summary>
/// 把对象按指定的键值保存到缓存中
/// </summary>
/// <param name="key">键值</param>
/// <param name="value">保存的对象</param>
public void SaveCaech(object key,object value)
{
EventSaveCache save = new EventSaveCache(SetCache);
IAsyncResult ar = save.BeginInvoke(key,value,new System.AsyncCallback(Results),null);
}
private void Results(IAsyncResult ar)
{
EventSaveCache fd = (EventSaveCache)((AsyncResult)ar).AsyncDelegate;
fd.EndInvoke(ar);
}
/// <summary>
/// 把对象按指定的键值保存到缓存中
/// </summary>
/// <param name="key">键值</param>
/// <param name="value">保存的对象</param>
protected virtual void SetCache(object key ,object value)
{
lock(_LockObj)
{
if(!_Cache.ContainsKey(key))
_Cache.Add(key,value);
}
}
public int Count
{
get
{
return _Cache.Count;
}
}
/// <summary>
/// 在缓存中删除指定键值的对象
/// </summary>
/// <param name="key">键值</param>
public virtual void DelObject(object key)
{
lock(_Cache.SyncRoot)
{
_Cache.Remove(key);
}
}
/// <summary>
/// 清除缓存中所有对象
/// </summary>
public virtual void Clear()
{
lock(_Cache.SyncRoot)
{
_Cache.Clear();
}
}
}
/// <summary>
///针对一条记录操作命令的缓存类
/// </summary>
public class CachePersistentCommand:Cache
{
/// <summary>
/// 把记录操作命令缓存到内存中
/// </summary>
/// <param name="key">标识</param>
/// <param name="value">值</param>
protected override void SetCache(object key, object value)
{
lock(_LockObj)
{
int count=0;
if(Container.Config.CommandsCache.ContainsKey(key))
count=(int) Container.Config.CommandsCache[key];
System.Collections.IList _list;
//如果缓存中已经存在这种命令的列表
if(_Cache.ContainsKey(key))
{
_list = (System.Collections.IList)_Cache[key];
if( count >0)//命令的缓存总数
{
if(_list.Count < count)//缓存数据量少于缓存总数
_list.Add(value);
}
else
{
if(_list.Count < Container.Config.CommandBuffer)//缓存数小于组件的默认列表
_list.Add(value);
}
}
else//如果不存在列表
{
if(count >0 || Container.Config.CommandBuffer >0)//如果组件允许对象缓存
{
_list = new System.Collections.ArrayList();
_list.Add(value);
_Cache.Add(key,_list);
}
}
}
}
/// <summary>
/// 从缓存中获取相关命令对象
/// </summary>
/// <param name="key">标识</param>
/// <returns>IPersistentCommand</returns>
public override object GetObject(object key)
{
if(_Cache.Contains(key))//如果命令存在缓冲中
{
foreach(IPersistentCommand cmd in (System.Collections.IList)_Cache[key])
{
if(!cmd.State)//命令是否可以过行锁定
if(cmd.Lock())//命令锁定
return cmd;
}
}
return null;
}
}