第一節 MongoDB介紹及下載與安裝
引言
MongoDB是一個介於關係數據庫和非關係數據庫之間的產品,是非關係數據庫當中功能最豐富,最像關係數據庫的。他支持的數據結構非常鬆散,是類似json的bjson格式,因此可以存儲比較複雜的數據類型。Mongo最大的特點是他支持的查詢語言非常強大,其語法有點類似於面向對象的查詢語言,幾乎可以實現類似關係數據庫單表查詢的絕大部分功能,而且還支持對數據建立索引。
它的特點是高性能、易部署、易使用,存儲數據非常方便。主要功能特性有:
- 面向集合存儲,易存儲對象類型的數據。
- 模式自由。
- 支持動態查詢。
- 支持完全索引,包含內部對象。
- 支持查詢。
- 支持複製和故障恢復。
- 使用高效的二進制數據存儲,包括大型對象(如視頻等)。
- 自動處理碎片,以支持雲計算層次的擴展性
- 支持RUBY,PYTHON,JAVA,C++,PHP等多種語言。
- 文件存儲格式爲BSON(一種JSON的擴展)
- 可通過網絡訪問
所謂“面向集合”(Collenction-Orented),意思是數據被分組存儲在數據集中,被稱爲一個集合(Collenction)。每個 集合在數據庫中都有一個唯一的標識名,並且可以包含無限數目的文檔。集合的概念類似關係型數據庫(RDBMS)裏的表(table),不同的是它不需要定 義任何模式(schema)。
模式自由(schema-free),意味着對於存儲在mongodb數據庫中的文件,我們不需要知道它的任何結構定義。如果需要的話,你完全可以把不同結構的文件存儲在同一個數據庫裏。
存儲在集合中的文檔,被存儲爲鍵-值對的形式。鍵用於唯一標識一個文檔,爲字符串類型,而值則可以是各中複雜的文件類型。我們稱這種存儲形式爲BSON(Binary Serialized dOcument Format)。
MongoDB服務端可運行在Linux、Windows或OS X平臺,支持32位和64位應用,默認端口爲27017。推薦運行在64位平臺,因爲MongoDB
在32位模式運行時支持的最大文件尺寸爲2GB。
MongoDB把數據存儲在文件中(默認路徑爲:/data/db),爲提高效率使用內存映射文件進行管理。
以上爲隨便摘的,其實就是非傳統的非關係數據庫,現在歸到文檔型數據庫分類之中,注意32位操作系統支持的最大文件爲2GB,所以做大文件海量儲存的朋友要選擇64位的系統安裝。開始我們的下載安裝之路吧。
一、下載
MongoDB的官網是:http://www.mongodb.org/
MongoDB最新版本下載在官網的DownLoad菜單下:http://www.mongodb.org/downloads
本人選擇的是Windows 32-bit 1.8.1版本
MongoDB For .net 驅動開發包位於官網的Driver菜單下(含其它語言開發鏈接):https://github.com/mongodb/mongo-csharp-driver/downloads
本人操作系統爲Windows7 專業版,選擇MongoDB版本爲Windows 32-bit 1.8.1,開發包爲VS2008版本
開始我們的安裝過程了
二、安裝
1.解壓mongodb-win32-i386-1.8.1.zip ,創建路徑C:\Program Files\mongodb ,將解壓後的Bin文件Copy to 此文件夾下
2.C:\Program Files\mongodb 下建立Data文件夾 C:\Program Files\mongodb\data ,然後分別建立db,log兩個文件夾,至此mongodb下有以下文件夾
C:\Program Files\mongodb\bin
C:\Program Files\mongodb\data\db
C:\Program Files\mongodb\data\log
在log文件夾下創建一個日誌文件MongoDB.log,即C:\Program Files\mongodb\data\log\MongoDB.log
完成以上工作後,你爲奇怪爲什麼要建立這些文件夾(因爲,Mongodb安裝需要這些文件夾,默認安裝是不用創建,但是文件都爲安裝到C:\data\下)
3.安裝類型
3.1 程序啓動方式
運行cmd.exe 進入DOS命中界面
> cd C:\Program Files\mongodb\bin
> C:\Program Files\mongodb\bin>mongod -dbpath "C:\Program Files\mongodb\data\db"
執行此命令即將mongodb的數據庫文件創建到C:\Program Files\mongodb\data\db 目錄,不出意外的會看到命令最後一行sucess的成功提示
此時數據庫就已啓動,該界面爲Mongo的啓動程序,關閉後可直接雙擊bin下的mongod.exe (注意是d,這個是啓動程序)
啓動程序開啓後,再運行mongo.exe 程序(注意沒有d) ,界面如下
測試數據庫操作
>help (查看相關信息)
>db.foo.insert({a:1}) (往foo表插入a,1字段值,foo表爲默認表)
>db.foo.find() (查看foo表數據)
結果如下:
可以看到插入了3條記錄分別人a,cctv,set 。
當mongod.exe被關閉時,mongo.exe 就無法連接到數據庫了,因此每次想使用mongodb數據庫都要開啓mongod.exe程序,所以比較麻煩,接下來我們將
MongoDB安裝爲windows服務吧
3.2 windows service方式
運行cmd.exe
> cd C:\Program Files\mongodb\bin
> C:\Program Files\mongodb\bin>mongod --dbpath "C:\Program Files\mongodb\data\db" --logpath "C:\Program Files\mongodb\data\log\MongoDB.log" --install --serviceName "MongoDB"
這裏MongoDB.log就是開始建立的日誌文件,--serviceName "MongoDB" 服務名爲MongoDB
運行命令成功爲如下圖:
引時服務已經安裝成功,運行
>NET START MongoDB (開啓服務)
>NET stop MongoDB (關閉服務)
>
> C:\Program Files\mongodb\bin>mongod --dbpath "C:\Program Files\mongodb\data\db" --logpath "C:\Program Files\mongodb\data\log\MongoDB.log" --remove --serviceName "MongoDB" (刪除,注意不是--install了)
其它命令可查閱help命令或官網說明。
查看服務
運行bin文件夾下mongo.exe 客戶端測試一下吧。測試同3.1相同 。
到此安裝就完成了。
第二節 爲什麼用MongoDB及.NET開發入門
本節問題:
- 爲什麼要用MongoDB
- MongoDB for .net驅動選擇
- MongoDB for VS插件介紹
- Demo介紹
一、爲什麼要用MongoDB
爲什麼要用MongoDB取代傳統關係型數據庫?其實不是取代,只是對傳統數據庫的文檔型補充。不是所有的數據都需要二維關係及多表對應的存儲和查詢,比如:文件的海量存儲,只需Key與Value形式的存儲及查詢,同時這種方式的存儲及查詢都是高效的,可查看GirdFS,GirdFS是MongoDB的大文件存儲系統,比如圖片、音頻、視頻;數據如果不需要實時分析統計(包含讀寫比高的),也可以使用KV形式存儲及查詢。MongoDB介於緩存與數據庫之間,存取速度遜於緩存但遠遠高於傳統數據庫。數據庫存儲以鍵值形式,你可能會認爲對數據關係的處理及分析挖掘不及傳統數據庫,理論上是如此,但是MongoDB加入了對LINQ的支持,相信可以彌補其不足之處。做項目要求穩,對於MongoDB的使用我們只是對傳統數據庫的一個類似二級緩存的補充,cache緩存及Memcached做爲一級緩存,MongoDB做爲二級緩存對海量大數據的一個緩衝查詢,最終纔是數據庫及物理文件的存儲。如果你對數據的分析挖掘統計不是實時的,也可以嘗試使用MongoDB直接存取數據,數據後期處理工作可通過MongoDB同步到傳統數據庫。(以上純屬個人理解)
用MongoDB做海量存儲,又出現另一個問題讀寫頻率與擴展?MongoDB可以根據應用程序的需要以兩種模式來運行。第一種是“單主”(single master)模式,只有一臺主服務器來處理所有的寫操作。讀操作能從中分離出去,通過任意數量的從服務器來進行讀操作,這有利於提高讀的可擴展性(使用場景:Sourceforge)。對於那些寫數據量很大或寫頻率過高,單臺主服務器無法處理的應用程序,可以使用MongoDB的自動分片模式。該模式下寫操作會自動分配到任意數量的“片”中(一般是一臺或一組MongoDB服務器),它們負責這部分數據集的寫和讀。無論使用哪種模式,MongoDB都會採取“強一致性”方法(你可以把MongoDB看成CAP理論中的C-P系統)。高可用性是通過將數據複製到多個MongoDB節點來實現的,每個節點都能及時成爲一個分片的主服務器——MongoDB會自動處理故障轉移。這能讓你在維持相當高的寫可用性的同時,擁有強一致性特性,這對一些用例來說非常重要。而MongoDB的分片支持複製和故障切換:Mongo數據庫支持服務器之間的數據複製,支持主-從模式及服務器之間的相互複製。MongoDB的自動分片模塊 ("mongos"). 自動分片可以用於構建一個大規模的可擴展的數據庫集羣,這個集羣可以併入動態增加的機器。(說細可參照此官方文檔)
二、MongoDB for .net驅動選擇
驅動源碼地址:https://github.com/mongodb/mongo-csharp-driver/downloads(第一章提到的)
項目應用:
第一款:mongodb-csharp 項目地址:http://github.com/samus/mongodb-csharp 應用很廣泛,更新速度也比較快,也加入了對LINQ的支持
第二款:simple-mongodb 項目地址:http://code.google.com/p/simple-mongodb 以JSON爲核心
第三款:NoRM 項目地址:http://github.com/atheken/NoRM 加入了對強類型的支持,是對一的補充
其它的也有,就不介紹了,經過綜合比較選擇了方案一,也就是第一章介紹的。方案一應該廣泛用於項目了,並且保持較快的更新速度,同時也加了LINQ的支持,對於項目求穩的朋友是最好的選擇,所以我也選擇了方案一samus驅動,下載的是(samus-mongodb-csharp-0.90.0.1.zip)下載選Tar.Zip包含源碼。另外一個包只有DLL。後面的文章中將一直使用samus開發包。
三、MongoDB for VS插件介紹
插件下載地址:http://www.cnblogs.com/ILoveSilence/archive/2010/08/10/mongowidget_1.html (園子里人做的)
插件和VS的數據源功能類似,想使用的就去看這篇博文吧。
四、Demo介紹
下載samus開發包後,你會發現裏面已經有了samples了,那就開始我們的入門之路了
這Demo都不寫了,直接拿來分析了
留意的朋友會發現,MongoDB的連接字符串是IP+端口,與傳統的數據庫引擎不同,包括數據的CURD操作都是鍵值方式,是不是有點像Memcached。
using System; using System.Configuration; using System.Linq; using MongoDB; using MongoDB.Configuration; using MongoDB.Linq; namespace Simple { /// <summary> /// Illustrates some simple operations on the database. /// Creating a database connection. /// Remove some documents. /// Insert some documents /// Find one document /// Find several documents and iterate through them. /// </summary> internal class MainClass { private IMongoCollection<Document> categories; private Mongo mongo; private IMongoDatabase simple; private class MyClass { public string Name { get; set; } public int Corners { get; set; } } private class SubClass : MyClass { public double Ratio { get; set; } } public static void Main(string[] args) { #region 以下爲被屏蔽源碼部分,我們先從SetUp方法開始 //var config = new MongoConfigurationBuilder(); //// COMMENT OUT FROM HERE //config.Mapping(mapping => //{ // mapping.DefaultProfile(profile => // { // profile.SubClassesAre(t => t.IsSubclassOf(typeof(MyClass))); // }); // mapping.Map<MyClass>(); // mapping.Map<SubClass>(); //}); //// TO HERE //config.ConnectionString("Server=127.0.0.1"); //using (Mongo mongo = new Mongo(config.BuildConfiguration())) //{ // mongo.Connect(); // try // { // var db = mongo.GetDatabase("TestDb"); // var collection = db.GetCollection<MyClass>(); // MyClass square = new MyClass() // { // Corners = 4, // Name = "Square" // }; // MyClass circle = new MyClass() // { // Corners = 0, // Name = "Circle" // }; // SubClass sub = new SubClass() // { // Name = "SubClass", // Corners = 6, // Ratio = 3.43 // }; // collection.Save(square); // collection.Save(circle); // collection.Save(sub); // var superclass = (from item in db.GetCollection<MyClass>("MyClass").Linq() // where item.Corners > 1 // select item.Corners).ToList(); // var subclass = (from item in db.GetCollection<SubClass>("MyClass").Linq() // where item.Ratio > 1 // select item.Corners).ToList(); // Console.WriteLine("Count by LINQ on typed collection: {0}", collection.Linq().Count(x => x.Corners > 1)); // Console.WriteLine("Count by LINQ on typed collection2: {0}", db.GetCollection<SubClass>().Linq().Count(x => x.Corners > 1)); // //Console.WriteLine("Count by LINQ on typed collection3: {0}", db.GetCollection<SubClass>().Count(new { Corners = Op.GreaterThan(1) })); // Console.WriteLine("Count on typed collection: {0}", collection.Count(new { Corners = Op.GreaterThan(1) })); // var coll = db.GetCollection("MyClass"); // var count = coll.Count(new Document("Corners", Op.GreaterThan(1))); // Console.WriteLine("Count: {0}", count); // Console.ReadKey(); // } // finally // { // mongo.Disconnect(); // } //} #endregion var main = new MainClass(); main.Setup(); main.Run(); Console.ReadLine(); } /// <summary> /// Setup the collection and insert some data into it. /// </summary> public void Setup() { //從配置文件讀取連接字符串 IP+端口 var connstr = ConfigurationManager.AppSettings["simple"]; if(String.IsNullOrEmpty(connstr)) throw new ArgumentNullException("Connection string not found."); //創建Mongo數據服務及連接 mongo = new Mongo(connstr); mongo.Connect(); //獲取數據庫實例(如果該實例不存,就會自動創建simple實例) simple = mongo["simple"]; //獲取表名(如果該表名不存在,就會自動創建categories表名) categories = simple.GetCollection<Document>("categories"); //添加記錄前清除所有記錄 Clean(); var names = new[] {"Bluez", "Jazz", "Classical", "Rock", "Oldies", "Heavy Metal"}; //循環插入記錄 doucment會自動生成鍵值_id,id的編碼體現了數據的插入順序 foreach(var name in names) categories.Insert(new Document {{"name", name}}); } public void Clean() { //刪除document name 爲Jazz的記錄 categories.Remove(new Document {{"name", "Jazz"}}); //remove documents with the name Jazz. //刪除所有記錄集 categories.Remove(new Document()); //remove everything from the categories collection. } public void Run() { //查找單條記錄 參數類型爲Document var category = categories.FindOne(new Document {{"name", "Bluez"}}); Console.WriteLine("The id findOne" + category["_id"]); //更新1 用鍵值ID讀取對象,並更新字段值,保存 var selector = new Document {{"_id", category["_id"]}}; category["name"] = "Bluess"; //The following will do the same thing. categories.Save(category); Console.WriteLine("Category after one update " + categories.FindOne(selector)); //更新2 Update參數1去更新參數2並保存 category["name"] = "Blues"; categories.Update(category, selector); Console.WriteLine("Category after two updates " + categories.FindOne(selector)); //Find it by _id that has been converted to a string now. var id = (category["_id"]).ToString(); //注意: 這裏id.ToString()與id.ToOid() (爲什麼類擴展這個方法,我也沒明白,是不是id!=24 位會出現轉義字符要替換掉) Console.WriteLine(string.Format("Found by string id[{0}] converted back to Oid[{1}]",id.ToString(),id.ToOid())); Console.WriteLine(categories.FindOne(new Document {{"_id", id.ToOid()}})); //Find(new Document()) is equivalent to FindAll(); //Specifying the cursor in a using block will close it on the server if we decide not //to iterate through the whole thing. Console.WriteLine("輸出所有對象........."); using(var all = categories.Find(new Document())) { foreach(var doc in all.Documents) Console.WriteLine(doc.ToString()); } mongo.Disconnect(); } } } //類擴展ToOid方法到string中 public static class OidExtensions { public static Oid ToOid(this string str) { if(str.Length == 24) return new Oid(str); return new Oid(str.Replace("\"", "")); } }
以上爲MongoDB的數據庫連接及CRUD操作(Document方式),我們來測試一下,數據庫實例,表,記錄是否創建成功了呢?
打開上一章提到的Bin文件夾下的Mongo.exe程序 按圖示輸入命令查看
入門Demo就演示到這裏了,有點簡單,我也在是一邊學習一邊分享。Demo就不提供下載了,都在samus裏面,只是我這邊加了註釋。
第三節 MongoDB下samus源碼初探
上一節我們在samus的simple例子簡單的入門了,這一節將要探討的問題寫個簡要
- 對象存儲
- 繼續關係對象的存儲
- LINQ體現
- 類關係分析
一、對象存儲
繼續在samus源碼上分析,依然是simple的例子。Demo中.net 3.5特性基本上都涉及了。
public static void Main(string[] args) { #region 以下爲Mongo配置及關係映射部分 //var config = new MongoConfigurationBuilder(); //COMMENT OUT FROM HERE //config.Mapping(mapping => //{ // mapping.DefaultProfile(profile => // { // profile.SubClassesAre(t => t.IsSubclassOf(typeof(MyClass))); // }); // mapping.Map<MyClass>(); // mapping.Map<SubClass>(); //}); // TO HERE #endregion //config.ConnectionString("Server=127.0.0.1"); //using (Mongo mongo = new Mongo(config.BuildConfiguration())) using (Mongo mongo = new Mongo("Server=127.0.0.1")) { mongo.Connect(); try { //索引器方式mogo["TestDb"] var db = mongo.GetDatabase("TestDb"); //老版不支持泛型的時候寫法是這樣的db.GetCollection("Name") ->看源碼重構了一個MongoCollection_1類 //將老版方法重構爲db.GetCollection<Documnet>("Name"); //此方法其實將類名反射爲集合 db.GetCollection<MyClass>("MyClass") var collection = db.GetCollection<MyClass>(); //.net 3.5集合初始化特性 創建3個對象(2個MyClass,1個子類SubClass) MyClass square = new MyClass() { Corners = 4, Name = "Square" }; MyClass circle = new MyClass() { Corners = 0, Name = "Circle" }; SubClass sub = new SubClass() { Name = "SubClass", Corners = 6, Ratio = 3.43 }; //保存對象 collection.Save(square); collection.Save(circle); collection.Save(sub); #region LINQ寫法讀取數據 //var superclass = (from item in db.GetCollection<MyClass>("MyClass").Linq() // where item.Corners > 1 // select item.Corners).ToList(); //var subclass = (from item in db.GetCollection<SubClass>("MyClass").Linq() // where item.Ratio > 1 // select item.Corners).ToList(); #endregion //Lambda寫法 //讀取集合MyClass所有對象 Console.WriteLine("Count by LINQ on typed collection: {0}", collection.Linq().Count(x => x.Corners > 1)); //讀取集合爲SubClass的對象(由於SubClass被保存到MyClass集合中了,故結果爲0) Console.WriteLine("Count by LINQ on typed collection2: {0}", db.GetCollection<SubClass>().Linq().Count(x => x.Corners > 1)); //Console.WriteLine("Count by LINQ on typed collection3: {0}", db.GetCollection<SubClass>().Count(new { Corners = Op.GreaterThan(1) })); //注:op 是Document的子類 雖然我們存的是其它對象,但所有的對象最終都是以Document類型存儲的, //也就意味檢索數據也是Document方式查找或統計了,以下Lambda方式的統計就體現了 //在基類中大家可以看到都是count(new Document())方式及條件查詢的,這裏介紹完了,下面的代碼就容易理解了 Console.WriteLine("Count on typed collection: {0}", collection.Count(new { Corners = Op.GreaterThan(1) })); var count = collection.Count(new Document("Corners", Op.GreaterThan(1))); Console.WriteLine("Count: {0}", count); Console.ReadKey(); } finally { mongo.Disconnect(); } } //var main = new MainClass(); //main.Setup(); //main.Run(); Console.ReadLine(); }
看一下結果:
在打開mongo.exe查看一下結果
是不是很奇怪,MyClass,SubClass對象又沒有標記爲可序列化,如何就被保存下來了?難道是通過反射對實現的,看看源碼
二、繼續關係對象的存儲
當數據保存爲文檔記錄時,MongoDB是如何識別這個兩類是有繼承關係的呢?我們接着下面的代碼修改一下繼續
先刪除上次的記錄,在mongo.exe中運行db.MyClass.drop() 刪除集合中的數據,查看更多操作集合的命令可執行db.MyClass.help
mongo.exe腳本命令官方介紹用的是Javascript腳本,從命名可以看出是它的影子。mongo.exe的腳本學習可參照這個鏈接
http://special.csdn.net/mongodb/index.html
public static void Main(string[] args) { #region 以下爲Mongo配置及關係映射部分 var config = new MongoConfigurationBuilder(); //COMMENT OUT FROM HERE 建立兩者的關係 config.Mapping(mapping => { mapping.DefaultProfile(profile => { profile.SubClassesAre(t => t.IsSubclassOf(typeof(MyClass))); }); mapping.Map<MyClass>(); mapping.Map<SubClass>(); }); // TO HERE #endregion config.ConnectionString("Server=127.0.0.1"); //將配置注入Mongo類中 using (Mongo mongo = new Mongo(config.BuildConfiguration())) { mongo.Connect(); try { //索引器方式mogo["TestDb"] var db = mongo.GetDatabase("TestDb"); //老版不支持泛型的時候寫法是這樣的db.GetCollection("Name") ->看源碼重構了一個MongoCollection_1類 //將老版方法重構爲db.GetCollection<Documnet>("Name"); //此方法其實將類名反射爲集合 db.GetCollection<MyClass>("MyClass") var collection = db.GetCollection<MyClass>(); //.net 3.5集合初始化特性 創建3個對象(2個MyClass,1個子類SubClass) MyClass square = new MyClass() { Corners = 4, Name = "Square" }; MyClass circle = new MyClass() { Corners = 0, Name = "Circle" }; SubClass sub = new SubClass() { Name = "SubClass", Corners = 6, Ratio = 3.43 }; //保存對象 collection.Save(square); collection.Save(circle); collection.Save(sub); #region LINQ寫法讀取數據 //var superclass = (from item in db.GetCollection<MyClass>("MyClass").Linq() // where item.Corners > 1 // select item.Corners).ToList(); //var subclass = (from item in db.GetCollection<SubClass>("MyClass").Linq() // where item.Ratio > 1 // select item.Corners).ToList(); #endregion //Lambda寫法 //讀取集合MyClass所有對象 Console.WriteLine("Count by LINQ on typed collection: {0}", collection.Linq().Count(x => x.Corners > 1)); //讀取集合爲SubClass的對象(由於SubClass被保存到MyClass集合中了,故結果爲0) Console.WriteLine("Count by LINQ on typed collection2: {0}", db.GetCollection<SubClass>().Linq().Count(x => x.Corners > 1)); //Console.WriteLine("Count by LINQ on typed collection3: {0}", db.GetCollection<SubClass>().Count(new { Corners = Op.GreaterThan(1) })); //注:op 是Document的子類 雖然我們存的是其它對象,但所有的對象最終都是以Document類型存儲的, //也就意味檢索數據也是Document方式查找或統計了,以下Lambda方式的統計就體現了 //在基類中大家可以看到都是count(new Document())方式及條件查詢的,這裏介紹完了,下面的代碼就容易理解了 Console.WriteLine("Count on typed collection: {0}", collection.Count(new { Corners = Op.GreaterThan(1) })); var count = collection.Count(new Document("Corners", Op.GreaterThan(1))); Console.WriteLine("Count: {0}", count); Console.ReadKey(); } finally { mongo.Disconnect(); } } //var main = new MainClass(); //main.Setup(); //main.Run(); Console.ReadLine(); }
結果:
再看mongo.exe中的記錄:
三、LINQ的體現
#region LINQ寫法讀取數據 var myCollection = (from item in db.GetCollection<MyClass>("MyClass").Linq() where item.Corners > 1 select item).ToList(); foreach (MyClass my in myCollection) { Console.WriteLine(my.Name+":"+my.Corners.ToString()); } var subCollection = (from item in db.GetCollection<SubClass>("MyClass").Linq() where item.Ratio > 1 select item).ToList(); foreach (SubClass subClass in subCollection) { Console.WriteLine(subClass.Name+":"+subClass.Ratio.ToString()); } var superclass = (from item in db.GetCollection<MyClass>("MyClass").Linq() where item.Corners > 1 select item.Corners).ToList(); var subclass = (from item in db.GetCollection<SubClass>("MyClass").Linq() where item.Ratio > 1 select item.Corners).ToList(); #endregion
結果:
以上就是LINQ的查找數據的方式,更多的方法還要研究一下源碼的MongDB下的LINQ文件夾。
四、類關係分析
以上四個類是MongoDB的基本業務類,從數據庫連接,到實例,集合的CRUD操作。
我們在看一下配置映射類圖:
配置類組合的類比較多,具體還有哪些功能,在後面的學習過程在繼續挖掘了。
好了這一節就到這裏了,繼續探討複雜對象的儲存及多組服務器配置。