MongoDB、Java及ORM

來源:互聯網
上載者:User
文章目錄
  • MongoDB簡介
  • 將MJORM庫添加到項目裡
  • 建立POJO
  • 建立XML對應檔
  • 整合
MongoDB簡介

目前有很多互相競爭的NoSQL產品,它們使用的方式不盡相同,但都能很好地解決大資料問題。MongoDB就是其中一款非常不錯的產品。MongoDB是面向文檔、無Schema的儲存解決方案,它用JSON風格的文檔展現、查詢、修改資料。

 MongoDB有很豐富的文檔,安裝和設定都很簡單,而且易於擴充。它支援大家熟知的複製、分區、索引和Map/Reduce等概念。MongoDB開源社區的規模很大,也很活躍。讓MongoDB引以為豪的是,包括Disney、Craigslist、Foursquare、Github和SourceForge在內的大型、高流量生產環境都已經部署了MongoDB。MongoDB是個開源項目,由DoubleClick前高管們創辦的10gen.com公司建立和維護。除了很積極地參與社區支援外,10gen也供應商業支援。

MongoDB和NoSQL的優劣勢

作為NoSQL解決方案,MongoDB的優勢是很容易上手。在我第一次深入研究NoSQL資料庫的時候,嘗試了很多基於Java的解決方案,我發現要搞清楚什麼是列族(column family)、Hadoop和HBase之間是什麼關係、ZooKeeper到底是什麼非常費時間。我最終想明白這些問題的時候,才明白Cassandra、HBase等產品都是非常完善的NoSQL解決方案。和其他解決方案相比,MongoDB則更容易掌握一些,開始寫代碼之前不需要理解太多的概念。

很顯然,MongoDB和任何軟體一樣都存在缺陷。在學習、使用MongoDB的過程中,我遇到過幾件可算是“陷阱”的事情:

  • 不要把它用成RDBMS。這一點看起來顯而易見,但在MongoDB裡建立、執行複雜查詢都很容易,以至於到了想用它做即時查詢的時候,你可能才會發現自己已經做過頭了,而且可能會碰到效能問題。(我以前就犯過這樣的錯)
  • MongoDB的索引是Binary Tree。如果你不太熟悉B-Tree,應該研究一下。查詢條件的順序要和建立索引的順序相匹配。
  • 精心設計索引。這和前面提到的B-Tree有關係。我剛開始建立的幾個索引都包含文檔裡的很多欄位,因為總是想著以後可能會查詢它們,這種想法你應該能夠理解。不要犯這樣的錯誤。我曾給一個很小的集合(大約一千萬條記錄)建立了一個索引,這個索引後來增長到17GB,比集合本身還要大。如果某個數組欄位可能會包含成百上千的條目,你可能不會給它建立索引。
  • MongoDB支援NoSQL的方法非常有趣,它用BSON儲存、用JSON表示,管理和Map/Reduce則用了JavaScript。這樣一來,等MongoDB發展的時間足夠久、和更流行的大資料解決方案一樣長的時候,MongoDB必然會出現一些奇怪的小問題,比如在NumberLong上使用等於運算子會判斷失敗。
MongoDB、控制台、驅動程式

MongoDB的管理通常可以在一個JavaScript用戶端控制台應用上進行,控制台應用能簡化資料移轉和操作等複雜任務;你也完全可以用JavaScript語言編程實現MongoDB的管理。在這篇文章裡,我們會示範控制台的使用。現在的MongoDB用戶端產品非常多,它們都具備能投入生產環境的品質,MongoDB社區也稱它們為驅動程式。一般來說,每種程式設計語言都有各自的驅動程式,這些驅動程式能覆蓋所有流行的程式設計語言,還有一些並不是很流行的程式設計語言。本文將展示MongoDB的Java驅動程式該如何使用,也會和使用ORM庫(MJORM)的方式進行比較。

MJORM簡介:MongoDB的ORM解決方案

NoSQL資料存放區還有很多有趣的問題需要解決,最近讓應用程式員比較關心的是對象關係映射(ORM)。ORM是指持久化資料和應用所用對象之間的映射,持久化資料過去都儲存在關係型資料庫裡。ORM能讓處理資料的過程更加流暢、更加貼近編寫應用的語言。

MongoDB面向文檔的架構讓它很容易進行ORM,因為它儲存的文檔本身就是對象。不過可惜的是,可用於MongoDB的Java ORM庫還不是很多,目前只有morphia(針對MongoDB的Java庫,是型別安全的)和spring-data(Spring Data綜合項目的MongoDB實現)。

這些ORM庫使用了大量註解,出於很多原因,我並不傾向於使用註解,其中最重要的是被註解的對象在多重專案之間的可移植性問題。所以我建立了mongo-Java-orm項目(MJORM,發音為me-yorm),它是針對MongoDB的Java ORM。MJORM使用MIT許可,放在了Google Code上。項目用Maven構建,Maven的工件庫目前託管在Google Code的Subversion伺服器上。寫這篇文章的時候,MJORM最新的穩定發布版本是0.15,個別項目已經在生產環境裡使用了。

MJORM入門將MJORM庫添加到項目裡

Maven使用者首先要將MJORM的Maven倉庫添加到pom.xml檔案裡,以便自己的項目能使用MJORM工件:

<repository>      <id>mjorm-webdav-maven-repo</id>     <name>mjorm maven repository</name>     <url>http://mongo-Java-orm.googlecode.com/svn/maven/repo/</url>     <layout>default</layout>  </repository>  

然後添加依賴本身:

<dependency>     <groupid>com.googlecode</groupid>     <artifactid>mongo-Java-orm</artifactid>     <version>0.15</version> </dependency> 

這樣你就能把MJORM類匯入到自己的應用裡並使用它們。如果你沒用Maven,那你需要手動下載MJORM庫,還有MJORM pom.xml裡列出的所有依賴。

建立POJO

依賴關係處理好之後,就開始編寫代碼吧。我們先編寫Java POJO:

class Author {     private String firstName;     private String lastName;     // ... setters and getters ... }  class Book {     private String id;     private String isbn;     private String title;     private String description;     private Author author;     // ... setters and getters ... } 

上面的物件模型描述了作者和書,作者有一個ID、還有姓氏和名字,書的描述資訊則包含ID、ISBN號、標題、描述資訊和作者。

可以看到書的ID屬性是一個String,它會適應成MongoDB的ObjectId類型,ObjectId類型是個十二位元組的二進位值,用十六進位的字串來表示。雖然MongoDB要求所有集合裡的每個文檔都要有一個唯一的ID,但並沒有要求ID必須是ObjectId類型。目前MJORM支援的ID類型只有ObjectId,而且會把它們表示成String。

你可能已經注意到,Author對象沒有ID。這是因為Author是Book文檔的子文檔,所以就沒必要非得有一個ID了。請記住,MongoDB的ID只需要放在一個集合的根層級文檔中。

建立XML對應檔

下一步是建立XML對應檔,MJORM會用這些對應檔把MongoDB文檔映射成對象。在本文的示範裡,我們會給兩個對象各建立一個文檔,但真正合理的做法是把所有的映射都放在一個XML檔案裡,或者根據實際需要進行分割。

下面是Author.mjorm.xml:

<?xml version="1.0"?> <descriptors>     <object class="Author">         <property name="firstName" />         <property name="lastName" />     </object> </descriptors> 

Book.mjorm.xml是:

<?xml version="1.0"?> <descriptors>     <object class="Book">         <property name="id" id="true" auto="true" />         <property name="isbn" />         <property name="title" />         <property name="description" />         <property name="author" />     </object> </descriptors> 

對應檔完全能自解釋。descriptors元素是根項目,所有的對應檔都要有。根項目下面是object元素,用來定義要被映射到MongoDB文檔的類。object會包含property元素,用來描述POJO的所有屬性,以及它們怎樣映射到MongoDB文檔的屬性。property元素至少要有一個name屬性,這是POJO屬性的名稱,也是MongoDB文件屬性的名稱。property元素還可以添加一個column屬性,指定MongoDB文檔裡備用的屬性名稱。

包含id屬性的property元素會被看作是對象的唯一識別碼。一個object元素可以只包含一個帶有id屬性的property元素。auto屬性是讓MJORM在持久化這個屬性時給它自動產生一個值。

要想瞭解有關XML對應檔更詳細的說明,請移步至Google Code上的MJORM項目。

整合

我們現在已經建立好了資料模型,還有告訴MJORM在資料寫入MongoDB時如何解析POJO、從MongoDB讀取資料時如何封裝POJO的對應檔,那我們就可以開始一段有趣的學習之旅了。首先我們必須開啟到MongoDB的串連:

Mongo mongo = new Mongo(     new MongoURI("mongodb://localhost/mjormIsFun")); // 10gen驅動程式 

Mongo對象來自10gen員工編寫的Java驅動程式。這個例子開啟了一個到本地MongoDB執行個體的串連,使用mjormIsFun資料庫。接下來我們建立MJORM裡的ObjectMapper。目前MJORM裡可用的ObjectMapper介面實現只有XmlDescriptorObjectMapper,它使用前面的XML Schema,MJORM以後的實現可能會支援註解或其他配置機制。

XmlDescriptorObjectMapper objectMapper = new XmlDescriptorObjectMapper(); mapper.addXmlObjectDescriptor(new File("Book.mjorm.xml")); mapper.addXmlObjectDescriptor(new File("Author.mjorm.xml")); 

我們建立了XmlDescriptorObjectMapper對象,並添加了對應檔。下一步我們會建立一個MJORM提供的MongoDao對象執行個體:

DB db = mongo.getDB("mjormIsFun"); // 10gen驅動程式 MongoDao dao = new MongoDaoImpl(db, objectMapper); 

我們先擷取了一個10gen驅動程式裡的DB對象執行個體。然後用DB對象和先前建立的ObjectMapper來建立MongoDao。現在已經做好了持久化資料的準備,那讓我們建立一個Book對象,並把它儲存到MongoDB裡去。

Book book = new Book(); book.setIsbn("1594743061"); book.setTitle("MongoDB is fun"); book.setDescription("...");  book = dao.createObject("books", book); System.out.println(book.getId()); // 4f96309f762dd76ece5a9595 

我們先建立了Book對象,賦值之後調用了MongoDao的createObject方法,兩個參數分別是集合名稱“books”和Book對象。MJORM接著會用先前建立的XML對應檔把Book轉換成DBObject(10gen的Java驅動程式所使用的基本物件類型),並把新的文檔持久化到“books”集合中。然後MJORM會返回Book對象的執行個體,返回的Book對象執行個體帶有產生的id屬性。重點要注意的是,MongoDB在預設情況下並不會要求建立好資料庫或集合後才能使用;MongoDB在需要的時候才會建立它們,這有時候會引起混亂。從MongoDB控制台上看到的新Book如下所示:

> db.books.find({_id:ObjectId("4f96309f762dd76ece5a9595")}).pretty() {     "_id":          ObjectId("4f96309f762dd76ece5a9595"),     "isbn":         "1594743061",     "title":        "MongoDB is fun",     "description":  "..." } 

讓我們來看看如果不使用MJORM,而是直接用10gen的Java驅動程式,createObject的過程是怎樣的:

Book book = new Book(); book.setIsbn("1594743061"); book.setTitle("MongoDB is fun"); book.setDescription("...");  DBObject bookObj = BasicDBObjectBuilder.start()     .add("isbn", book.getIsbn())     .add("title",book.getTitle())     .add("description",book.getDescription())     .get();  // ‘db’是我們先前建立的DB對象 DBCollection col = db.getCollection("books"); col.insert(bookObj);  ObjectId id = ObjectId.class.cast(bookObj.get("_id")); System.out.println(id.toStringMongod()); // 4f96309f762dd76ece5a9595 

現在我們來查詢一下對象:

Book book = dao.readObject("books", "4f96309f762dd76ece5a9595", Book.class); System.out.println(book.getTitle()); // "MongoDB is fun" 

readObject方法用指定的id從特定集合中讀取檔案,然後將檔案轉換成相應的類(會再次使用先前的對應檔)並返回。

敏銳的你可能已經察覺到我們的Book還沒Author,但Book仍然被持久化了。這正是MongoDB的無Schema特性。除了id之外,我們不能要求集合裡的文檔包含任何屬性,所以在MongoDB裡建立沒有Author的Book是完全沒有問題的。讓我們給Book添加一位Author並更新:

Author author = new Author(); author.setFirstName("Brian"); author.setLastName("Dilley");  book.setAuthor(author);  dao.updateObject("books", "4f96309f762dd76ece5a9595", book); 

現在的Book包含了Author,也持久化到了MongoDB。讓我們從MongoDB控制台上看看新的Book:

> db.books.find({_id:ObjectId("4f96309f762dd76ece5a9595")}).pretty() {     "_id":          ObjectId("4f96309f762dd76ece5a9595"),     "isbn":         "1594743061",     "title":        "MongoDB is fun",     "description":  "..."     "author": {         "firstName": "Brian",         "lastName": "Dilley"     } } 

正如你所看到的,持久化的Book現在包含一個作者。接著再看看不使用MJORM的情況:

Author author = new Author(); author.setFirstName("Brian"); author.setLastName("Dilley");  book.setAuthor(author);  DBObject bookObj = BasicDBObjectBuilder.start()     .add("isbn", book.getIsbn())     .add("title",book.getTitle())     .add("description",book.getDescription())     .push("author")         .add("firstName", author.getFirstName())         .add("lastName", author.getLastName())         .pop()     .get();  DBCollection col = db.getCollection("books"); col.update(new BasicDBObject("_id", bookObj.get("_id")), bookObj); 

在這篇文章裡我們就不深入介紹MongoDao的所有方法了。如果你想在項目裡使用MJORM,推薦你看看MJORM項目的文檔,或者是MJORM項目提供的MongoDao介面。

結論

希望這篇文章能讓大家對MongoDB和MJORM開始感興趣。方興未艾的MongoDB是個很優秀的NoSQL資料存放區產品,有很多很不錯的特性。如果你要在Java項目裡使用MongoDB,那你可以考慮用MJORM庫來滿足ORM需求。要是能提出功能需求、Bug報告、文檔,或給源碼打補丁,我們將不勝感激!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.