最近研究了一下NOSQL,現整理目錄以下:程序員
1、關係數據庫的瓶頸;web
2、NOSQL概述;sql
3、NOSQL中的熱門數據庫MongoDB介紹及安裝配置;mongodb
4、MongoDB開發模式及實戰;數據庫
從90年代到至今,關係數據庫扮演了最重要的角色,它的性能,可擴展性、穩定性、數據的備份和恢復機制等都很是好,關係數據庫發展到如今已經很是成熟,它提供給使用者的是一整套體系,包括數據存儲、數據備份恢復、數據加解密、應用開發驅動、圖形化配置維護工具、安全策略等等。圖1中展現了世界上各類數據庫的使用比例,從這個圖上咱們明顯看得出它的霸主地位。windows
圖1:各類數據庫的使用比例數組
不過隨着信息技術的快速發展,Web發展也從Web1.0發展到了Web2.0時代,網站開始快速發展,博客、電子商務、微博、社區等Web應用已經引領了時代潮流,它們的網絡流量很是巨大,爲了解決這個問題,不少IT公司都採起了一系列優化措施,主要優化措施以下:緩存
一、Cache+SQL;安全
爲了提升網站的性能,咱們常常會把一些讀取訪問頻率比較高,更新頻率低的數據存儲在內存中,一方面能夠提升用戶的體驗,另一方面能夠減輕數據庫的訪問壓力;服務器
2 、讀寫分離;
還有一種好的方式就是讀寫分離,例如咱們能夠把內網應用系統產生的數據對稱的發佈到互聯網的數據庫中,這樣互聯網應用的訪問都是從外網數據庫中讀取,內網數據庫大部分都是增、刪、改等操做,這樣也能大幅度提升應用的性能;
三、分表分庫;
隨着Web2.0的高速發展,在Cache+SQL、數據庫主從複製讀寫分離的優化的情形下,關係數據庫主庫的寫壓力出現瓶頸,數據量的持續猛增,訪問的高併發狀況之下,關係數據庫會出現嚴重的鎖問題,這時開始流行分表分庫的方式來緩解寫壓力和數據增加的擴展問題,很早以前我作的一個應用系統,就出現了這個需求,隨着數據量的沉澱,數據庫變得很是龐大,數據庫和日誌文件達到了10幾個G,有些表裏面有上千萬條數據,用戶在使用過程當中,進行操做時常常會卡住,有時候一等就是幾秒或幾十秒,客戶很是不滿意,後來咱們討論以後就採起了數據庫方面,一年一個庫進行分庫,某些數據量大的表採用拆分,例如一個月產生一個表,還有把一個表中的字段拆分到多個表中等;
經過以上優化咱們系統的性能會提升很大一塊,每秒查詢率方面能夠達到:幾百qps到幾千qps不等,數據庫大小能夠達到1T左右,不過隨着訪問量和數據量的加大,關係數據庫很難繼續高效率的擔當,採用分表分庫能夠在必定程度上下降這個瓶頸,不過它下降了應用的可擴展性,帶來了巨大的技術和開發成本,例如一個需求的變動,可能就會致使一種新的分庫分表方式。
關係數據庫中基本上都會存儲一些大文本和附件信息,致使數據庫很是的大,在作數據庫恢復的時候就會很是的慢,例如1000萬3KB的大文本就接近30G的大小、100萬200K的附件就是200G,若是能把這些大文本和大附件從關係數據庫中省去,咱們的關係數據庫將會變得很小從而很容易優化。
綜上,關係數據庫很強大,可是它並不能很好的應付全部的應用場景。關係數據庫的擴展性差(須要複雜的技術來實現),大數據下IO壓力大,表結構更改困難,正是當前使用關係數據庫的開發人員面臨的問題。
一、什麼是NOSQL?
隨着web2.0的快速發展,非關係型、分佈式數據存儲獲得了快速的發展,它們不保證關係數據的ACID特性。NoSQL概念在2009年被提了出來。NoSQL最多見的解釋是「non-relational」,「Not Only SQL」也被不少人接受。(「NoSQL」一詞最先於1998年被用於一個輕量級的關係數據庫的名字。)
NoSQL被咱們用得最多的當數key-value存儲,固然還有其餘的文檔型的、列存儲、圖型數據庫、xml數據庫等,見圖2。在NoSQL概念提出以前,這些數據庫就被用於各類系統當中,可是卻不多用於web互聯網應用。
圖2:非關係數據庫種類
二、NOSQL的發展情況如何?
目前NOSQL至關火爆,微博、電子商務、博客、社區、論壇等大數據量高併發的互聯網應用中基本都用到了它,大的IT巨頭們都在各自的互聯網架構中加入了NOSQL解決方案,甚至擁有本身的NOSQL產品,各類NOSQL產品百花齊放,如圖3,在2010年以後NOSQL達到井噴之勢,其中mongoDb發展勢頭最猛也最火熱。
圖3:NOSQL發展趨勢
三、NOSQL和關係數據庫的關係?
我以爲關係數據庫和NOSQL是一種相輔相成緊密結合的關係,咱們須要根據具體的應用場景來選擇對應數據庫,若是你的應用的數據量很小,那麼關係數據庫就足夠了,並且性能、效率、穩定性、安全都是有保證的;若是你的應用場景中涉及超大的數據量(包含大文本、多附件),例如量級在幾百G或T級,那麼能夠考慮用關係數據庫和NOSQL結合的方式來解決,關係數據庫存儲相應的關係數據,NOSQL數據庫存儲像大文本、對象、附件等類型數據,這樣是一種最優的解決方案;
一、概念
三、功能
第一步:下載安裝包:官方下載地址←單擊此處,若是是win系統,注意是64位仍是32位版本的,請選擇正確的版本。
第二步:新建目錄「D:\MongoDB」,解壓下載到的安裝包,找到bin目錄下面所有.exe文件,拷貝到剛建立的目錄下。
第三步:在「D:\MongoDB」目錄下新建「data」文件夾,它將會做爲數據存放的根文件夾。
配置Mongo服務端:
打開CMD窗口,按照以下方式輸入命令:
> d:
> cd D:\MongoDB
> mongod --dbpath D:\MongoDB\data
配置成功後會看到以下圖4:
第四步:安裝爲windows服務
mongod --install --serviceName MongoDB --serviceDisplayName MongoDB --logpath D:\MongoDB\log\MongoDB.log --dbpath D:\MongoDB\data --directoryperdb,執行成功以後在windows服務中能夠看到名稱爲MongoDB的服務,開啓就能夠了,這樣能避免exe CMD命令框的煩惱;
一、開發模式
對於MongoDB的開發模式,咱們能夠採用相似高速服務框架HSF的模式進行架構,見圖5,首先在基礎構件層中咱們把MongoDB的驅動封裝到基類庫Inspur.Finix.DAL中,
而後在領域層採用小三層架構模式調用基礎構件層的數據服務,展示層在經過AJAX+JSON+Filter方式經過服務的形式調用業務層,展示層就能夠很好的利用返回的JSON串實現頁面的功能。
圖5:開發模式
二、開發實戰
C#驅動有不少種比較經常使用的是官方驅動和samus驅動。samus驅動除了支持通常形式的操做以外,還支持linq方式操縱數據
(1)基礎構件層封裝咱們採用samus驅動進行封裝,代碼以下:
public class MongoDBAccess : IDisposable { /// <summary> /// 數據庫別名 /// </summary> private string _dataBaseAlias = "Noah.MongoDB"; /// <summary> /// 集合名 /// </summary> public string _collectionName { get; set; } // 定義mongo服務 private Mongo _mongo = null; // 獲取databaseName對應的數據庫,不存在則自動建立 private IMongoDatabase _mongoDatabase = null; public MongoCollection<Document> MongoCollection; /// <summary> /// 構造函數 /// </summary> /// <param name="dataBaseAlias"></param> /// <param name="collectionName"></param> public MongoDBAccess(string dataBaseAlias, string collectionName) { _dataBaseAlias = dataBaseAlias; _collectionName = collectionName; init(); } /// <summary> /// 初始化 /// </summary> private void init() { DatabaseConfigManager dcm = DatabaseConfigManager.Create(); // 根據別名獲得鏈接串 string connStr = dcm.GetPrimaryConnection(_dataBaseAlias); // 把conn進行拆分 StringTokenizer st = new StringTokenizer(connStr, ";"); string conn = st.GetValueByIndex(0); // 定義mongo服務 _mongo = new Mongo(conn); _mongo.Connect(); st = new StringTokenizer(st.GetValueByIndex(1), "="); string databaseName = st.GetValueByIndex(1); // 獲取databaseName對應的數據庫,不存在則自動建立 if (string.IsNullOrEmpty(databaseName) == false) _mongoDatabase = _mongo.GetDatabase(databaseName); //獲取collectionName對應的集合,不存在則自動建立 MongoCollection = _mongoDatabase.GetCollection<Document>(_collectionName) as MongoCollection<Document>; } /// <summary> /// 切換到指定的數據庫 /// </summary> /// <param name="dbName"></param> /// <returns></returns> public IMongoDatabase UseDb(string dbName) { if (string.IsNullOrEmpty(dbName)) throw new ArgumentNullException("dbName"); _mongoDatabase = _mongo.GetDatabase(dbName); return _mongoDatabase; } /// <summary> /// 獲取當前鏈接的數據庫 /// </summary> public IMongoDatabase CurrentDb { get { if (_mongoDatabase == null) throw new Exception("當前鏈接沒有指定任何數據庫。請在構造函數中指定數據庫名或者調用UseDb()方法切換數據庫。"); return _mongoDatabase; } } /// <summary> /// 獲取當前鏈接數據庫的指定集合【依據類型】 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public IMongoCollection<T> GetCollection<T>() where T : class { return this.CurrentDb.GetCollection<T>(); } /// <summary> /// 獲取當前鏈接數據庫的指定集合【根據指定名稱】 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="name">集合名稱</param> /// <returns></returns> public IMongoCollection<T> GetCollection<T>(string name) where T : class { return this.CurrentDb.GetCollection<T>(name); } /// <summary> /// 使用GridFS保存附件 /// </summary> /// <param name="byteFile"></param> /// <returns></returns> public string GridFsSave(byte[] byteFile) { string filename = Guid.NewGuid().ToString(); //這裏GridFile構造函數有個重載,bucket參數就是用來替換那個建立集合名中默認的"fs"的。 GridFile gridFile = new GridFile(_mongoDatabase); using (GridFileStream gridFileStream = gridFile.Create(filename)) { gridFileStream.Write(byteFile, 0, byteFile.Length); } return filename; } /// <summary> /// 讀取GridFs附件 /// </summary> /// <param name="filename"></param> /// <returns></returns> public byte[] GridFsRead(string filename) { GridFile gridFile = new GridFile(_mongoDatabase); byte[] bytes; using (GridFileStream gridFileStream = gridFile.OpenRead(filename)) { bytes = new byte[gridFileStream.Length]; gridFileStream.Read(bytes, 0, bytes.Length); } return bytes; } public void GridFsDelete(string filename) { GridFile gridFile = new GridFile(_mongoDatabase); gridFile.Delete(new Document("filename", filename)); } /// <summary> /// 資源釋放 /// </summary> public void Dispose() { if (_mongo != null) { _mongo.Dispose(); _mongo = null; } } }
(2)領域層部分代碼
public class KNOWLEDGE_SOCKDAL { public KNOWLEDGE_SOCKDAL() { } /// <summary> /// 保存一個對象 /// </summary> /// <param name="model"></param> public void Add(KNOWLEDGE_SOCK model) { try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { mm.GetCollection<KNOWLEDGE_SOCK>().Insert(model); } } catch (Exception ex) { ExceptionManager.Handle(ex); } } /// <summary> /// 保存附件 /// </summary> /// <param name="file"></param> /// <returns></returns> public string SaveAttach(byte[] file) { string fileName = string.Empty; try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { fileName = mm.GridFsSave(file); } } catch (Exception ex) { ExceptionManager.Handle(ex); } return fileName; } /// <summary> /// 讀取附件 /// </summary> /// <param name="fileName"></param> /// <returns></returns> public byte[] ReadAttach(string fileName) { try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { mm.GetCollection<KNOWLEDGE_SOCK>(); return mm.GridFsRead(fileName); } } catch (Exception ex) { ExceptionManager.Handle(ex); } return null; } /// <summary> /// 刪除附件 /// </summary> /// <param name="fileName"></param> public void DeleteAttach(string fileName) { try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { mm.GetCollection<KNOWLEDGE_SOCK>(); mm.GridFsDelete(fileName); } } catch (Exception ex) { ExceptionManager.Handle(ex); } } /// <summary> /// 更新 /// </summary> /// <param name="model"></param> public void Update(KNOWLEDGE_SOCK model) { try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { var query = new Document("Know_Code", model.Know_Code); mm.GetCollection<KNOWLEDGE_SOCK>().Update(model, query); } } catch (Exception ex) { ExceptionManager.Handle(ex); } } /// <summary> /// 刪除 /// </summary> /// <param name="id"></param> public void Delete(string id) { try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { var query = new Document("Know_Code", id); mm.GetCollection<KNOWLEDGE_SOCK>().Remove(query); } } catch (Exception ex) { ExceptionManager.Handle(ex); } } /// <summary> /// 查詢特定一條 /// </summary> /// <param name="id"></param> /// <returns></returns> public KNOWLEDGE_SOCK FindOne(string id) { KNOWLEDGE_SOCK catalog = new KNOWLEDGE_SOCK(); try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { var query = new Document("Know_Code", id); catalog = mm.GetCollection<KNOWLEDGE_SOCK>().FindOne(query); } } catch (Exception ex) { ExceptionManager.Handle(ex); } return catalog; } /// <summary> /// 根據條件查詢 /// </summary> /// <param name="js"></param> /// <returns></returns> public List<KNOWLEDGE_SOCK> Find(string js) { List<KNOWLEDGE_SOCK> catalogs = new List<KNOWLEDGE_SOCK>(); try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { string jsStr = @" function(){ return " + js + ";}"; catalogs = mm.GetCollection<KNOWLEDGE_SOCK>().Find(Op.Where(jsStr)).Documents.ToList(); } } catch (Exception ex) { ExceptionManager.Handle(ex); } return catalogs; } /// <summary> /// 查詢所有 /// </summary> /// <returns></returns> public List<KNOWLEDGE_SOCK> FindAll() { List<KNOWLEDGE_SOCK> catalogs = new List<KNOWLEDGE_SOCK>(); try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { catalogs = mm.GetCollection<KNOWLEDGE_SOCK>().FindAll().Documents.ToList(); } } catch (Exception ex) { ExceptionManager.Handle(ex); } return catalogs; } /// <summary> /// 返回數量 /// </summary> /// <param name="js"></param> /// <returns></returns> public int GetCount(string js) { int count = 0; try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { string jsStr = @" function(){ return " + js + ";}"; count = mm.GetCollection<KNOWLEDGE_SOCK>().Find(Op.Where(jsStr)).Documents.Count(); } } catch (Exception ex) { ExceptionManager.Handle(ex); } return count; } public List<KNOWLEDGE_SOCK> Find(string js, int pageSize, int pageIndex) { List<KNOWLEDGE_SOCK> list = new List<KNOWLEDGE_SOCK>(); try { using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, "")) { string jsStr = @" function(){ return " + js + ";}"; list = mm.GetCollection<KNOWLEDGE_SOCK>().Find(Op.Where(jsStr)).Documents.OrderBy(x=>x.Know_CreateTime).Skip(pageSize * (pageIndex-1)).Take(pageSize).ToList(); } } catch (Exception ex) { ExceptionManager.Handle(ex); } return list; } }