最近在編寫一個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;
}
}