前言html
本來上一篇是打算寫分離數據層的,可是在思考的過程中發現分離數據層的時候,有一些操做是要依賴分佈式鎖的,所以先寫了分佈式鎖。web
對於有些項目的數據層提供的是業務接口的(返回業務所需的數據),那麼當數據層壓力逐漸增大的時候,如須要使用緩存的時候,就須要開發人員去修改相應的數據接口使其使用緩存,緩存和各類數據查詢接口交錯在一塊兒,整個數據層的代碼變得很是混亂,連重構都沒法進行,只能推倒重作。因此不少的文章中,在講解數據層的時候,都是使用統一的數據接口,如:Find、Add、Save等,那麼當須要緩存的時候,就能夠在Find中直接擴展使其支持緩存,甚至能夠引入緩存配置管理,對於不一樣的表之間進行可調度的緩存週期管理,使開發人員不須要知道緩存的存在,他們仍是使用原先的Find,可是速度卻更快了,又或者冷熱數據管理、搜索引擎等,這即是大神們在通過多年開發總結下來的經驗。數據庫
將數據層從項目中分離出來成爲一個獨立的項目,並將其發佈於獨立的服務器,相對於單機系統而言,有以下幾個優勢:緩存
一、便於整合各方資源服務器
二、下降成本網絡
三、每一個層的性能更加優秀且可伸縮性強,在不斷增長的負荷下,能夠便利的增長節點數量。mvc
四、某些次服務層出現錯誤的時候,不會致使項目的總體癱瘓。app
五、不一樣層次可用不一樣語言實現框架
有優勢就有缺點,最大的缺點就是較單機系統而言,分佈式系統更加複雜,不只系統自己結構會變得複雜,不一樣組件間的網絡會引入影響因素,調試困難等等。socket
雖然有很多的缺點,可是不去實踐是不會發現另外一番天地的,不去挑戰看看永遠都只是侷限在單機系統上,也不用懼怕會遇到哪些問題,畢竟只有發現問題以後,才能想辦法解決,這是從書上沒法學習到的,那麼咱們就開始今天的文章吧。
基礎CRUD
數據層是提供於數據庫進行操做的中間件,最基礎的功能就是CRUD,單機系統當中,調用CRUD接口的時候,要麼經過拼接SQL要麼經過ORM直接鏈接數據庫,而因爲如今是分佈式的,所以原先的調用方式就須要經過通訊協議來實現了,假設原先的接口爲:
public class DbResult { public bool Error { get; set; } public object Data { get; set; } } public interface IDb { DbResult Find(Dictionary<string, object> query); DbResult Add(object entity); DbResult Save(object entity); DbResult Remove(object entity); }
數據層那端的Find是以Query Object模式實現的,具體的格式能夠查看此文章--《Query Object--查詢對象模式(上)》、《Query Object--查詢對象模式(下)》。
這裏的數據層項目,若是使用原先抽取的mvcHandler方式來實現,那麼IService的派生類就須要使用HttpWebRequest來實現了,大體的實現思路就是將相應的方法最後轉換成調用數據服務,Find實現代碼以下:
public DbResult Find(Dictionary<string, object> query) { var url = string.Format("{0}/{1}/{2}", ConnectionUri, this.table, "find"); var req = (HttpWebRequest)HttpWebRequest.Create(url); req.Method = "Post"; req.Accept = "text/plain, */*; q=0.01"; req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; req.Timeout = 1000 * 30; req.KeepAlive = true; try { byte[] bytes = Encoding.UTF8.GetBytes( JsonConvert.SerializeObject(query)); req.ContentLength = bytes.Length; using (var reqStream = req.GetRequestStream()) { Stream requestStream = req.GetRequestStream(); requestStream.Write(bytes, 0, bytes.Length); } var res = new DbResult(); using (var resp = (HttpWebResponse)req.GetResponse()) { using (var respStream = resp.GetResponseStream()) { using (var reader = new StreamReader(respStream, Encoding.UTF8)) { string respContent = reader.ReadToEnd(); return JsonConvert.DeserializeObject(respContent); } } } } catch { return new DbResult { Error = true }; } }
事務
有了基礎的CRUD之後,接下來就要實現事務了,若是參考單機系統來實現事務的話,那麼開啓事務之後,若是業務層出現問題致使主機重啓或宕機,那麼數據層的事務將會沒法關閉,從而引起問題。
所以須要使用其餘的方式來實現,觀察事務能夠得出從事務開啓到提交是一個總體,只有事務提交的時候才須要有狀態來斷定事務的執行狀況,而事務開啓時並能夠不須要有執行結果的斷定,所以能夠將事務當作一個隊列,而中間的每個CUD操做能夠當作是它的元素,而每個操做須要知道對應的是哪一個表、執行哪一個操做以及相應的表數據便可,代碼實現以下:
public class TransactionAction { public string Table { get; set; } public string Name { get; set; } public object Data { get; set; } } //IDb public interface IDb { //其餘省略 void BeginTx(); DbResult CommitTx(); } //IDb實現 private List actions; public void BeginTx() { this.actions = new List(); } public DbResult CommitTx() { //http訪問數據層並設置actions爲null } public DbResult Add(object entity) { if (this.actions != null) { this.actions.Add(new TransactionAction { Name = "add", Table = this.table, Data = entity }); } else { //單個增長 } }
結束語
到這裏數據層的分離基本上就完成了,若是想要更高效的數據獲取,能夠將訪問方式修改爲socket,之因此不直接使用WPF或者webService是由於這都是基於C#來開發的,並且若是直接使用現成的框架來用的話,能學到的東西就很少了。
就到這裏了,若是有什麼問題或者錯誤的話,請給我留言,謝謝。