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