Neo4j 简介
數據存儲一般是應用開發(fā)中不可或缺的組成部分。應用運行中產生的和所需要的數據被以特定的格式持久化下來。應用開發(fā)中很常見的一項任務是在應用本身的領域對象模型與數據存儲格式之間進行相互轉換。如果數據存儲格式與領域對象模型之間比較相似,那么進行轉換所需的映射關系更加自然,實現(xiàn)起來也更加容易。對于一個特定的應用來說,其領域對象模型由應用本身的特征來決定,一般采用最自然和最直觀的方式來進行建模。所以恰當的選擇數據存儲格式就顯得很重要。目前最常見的數據存儲格式是關系數據庫。關系數據庫通過實體 - 關系模型(E-R 模型)來進行建模,即以表和表之間的關系來建模。在實際開發(fā)中可以使用的關系數據庫的實現(xiàn)非常多,包括開源的和商用的。關系數據庫適合用來存儲數據條目的類型同構的表格型數據。如果領域對象模型中不同對象之間的關系比較復雜,則需要使用繁瑣的對象關系映射技術(Object-Relationship Mapping,ORM)來進行轉換。
對于很多應用來說,其領域對象模型并不適合于轉換成關系數據庫形式來存儲。這也是非關系型數據庫(NoSQL)得以流行的原因。NoSQL 數據庫的種類很多,包括鍵值對數據庫、面向文檔數據庫和圖形數據庫等。本文中介紹的 Neo4j 是最重要的圖形數據庫。Neo4j 使用數據結構中圖(graph)的概念來進行建模。Neo4j 中兩個最基本的概念是節(jié)點和邊。節(jié)點表示實體,邊則表示實體之間的關系。節(jié)點和邊都可以有自己的屬性。不同實體通過各種不同的關系關聯(lián)起來,形成復雜的對象圖。Neo4j 同時提供了在對象圖上進行查找和遍歷的功能。
對于很多應用來說,其中的領域對象模型本身就是一個圖結構。對于這樣的應用,使用 Neo4j 這樣的圖形數據庫進行存儲是最適合的,因為在進行模型轉換時的代價最小。以基于社交網絡的應用為例,用戶作為應用中的實體,通過不同的關系關聯(lián)在一起,如親人關系、朋友關系和同事關系等。不同的關系有不同的屬性。比如同事關系所包含的屬性包括所在公司的名稱、開始的時間和結束的時間等。對于這樣的應用,使用 Neo4j 來進行數據存儲的話,不僅實現(xiàn)起來簡單,后期的維護成本也比較低。
Neo4j 使用“圖”這種最通用的數據結構來對數據進行建模使得 Neo4j 的數據模型在表達能力上非常強。鏈表、樹和散列表等數據結構都可以抽象成用圖來表示。Neo4j 同時具有一般數據庫的基本特性,包括事務支持、高可用性和高性能等。Neo4j 已經在很多生產環(huán)境中得到了應用。流行的云應用開發(fā)平臺 Heroku 也提供了 Neo4j 作為可選的擴展。
在簡要介紹完 Neo4j 之后,下面介紹 Neo4j 的基本用法。
Neo4j 基本使用
在使用 Neo4j 之前,需要首先了解 Neo4j 中的基本概念。
節(jié)點和關系
Neo4j 中最基本的概念是節(jié)點(node)和關系(relationship)。節(jié)點表示實體,由?org.neo4j.graphdb.Node?接口來表示。在兩個節(jié)點之間,可以有不同的關系。關系由?org.neo4j.graphdb.Relationship?接口來表示。每個關系由起始節(jié)點、終止節(jié)點和類型等三個要素組成。起始節(jié)點和終止節(jié)點的存在,說明了關系是有方向,類似于有向圖中的邊。不過在某些情況,關系的方向可能并沒有意義,會在處理時被忽略。所有的關系都是有類型的,用來區(qū)分節(jié)點之間意義不同的關系。在創(chuàng)建關系時,需要指定其類型。關系的類型由?org.neo4j.graphdb.RelationshipType?接口來表示。節(jié)點和關系都可以有自己的屬性。每個屬性是一個簡單的名值對。屬性的名稱是?String?類型的,而屬性的值則只能是基本類型、String?類型以及基本類型和?String?類型的數組。一個節(jié)點或關系可以包含任意多個屬性。對屬性進行操作的方法聲明在接口org.neo4j.graphdb.PropertyContainer?中。Node?和?Relationship?接口都繼承自?PropertyContainer?接口。PropertyContainer 接口中常用的方法包括獲取和設置屬性值的?getProperty 和 setProperty。下面通過具體的示例來說明節(jié)點和關系的使用。
該示例是一個簡單的歌曲信息管理程序,用來記錄歌手、歌曲和專輯等相關信息。在這個程序中,實體包括歌手、歌曲和專輯,關系則包括歌手與專輯之間的發(fā)布關系,以及專輯與歌曲之間的包含關系。清單 1?給出了使用 Neo4j 對程序中的實體和關系進行操作的示例。
清單 1. 節(jié)點和關系的使用示例
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | private static enum RelationshipTypes implements RelationshipType { ???PUBLISH, CONTAIN } public void useNodeAndRelationship() { ???GraphDatabaseService db = new EmbeddedGraphDatabase("music"); ???Transaction tx = db.beginTx(); ???try { ???????Node node1 = db.createNode(); ???????node1.setProperty("name", "歌手 1"); ???????Node node2 = db.createNode(); ???????node2.setProperty("name", "專輯 1"); ???????node1.createRelationshipTo(node2, RelationshipTypes.PUBLISH); ???????Node node3 = db.createNode(); ???????node3.setProperty("name", "歌曲 1"); ???????node2.createRelationshipTo(node3, RelationshipTypes.CONTAIN); ???????tx.success(); ???} finally { ???????tx.finish(); ???} } |
在?清單 1?中,首先定義了兩種關系類型。定義關系類型的一般做法是創(chuàng)建一個實現(xiàn)了 RelationshipType 接口的枚舉類型。RelationshipTypes 中的 PUBLISH 和 CONTAIN 分別表示發(fā)布和包含關系。在 Java 程序中可以通過嵌入的方式來啟動 Neo4j 數據庫,只需要創(chuàng)建 org.neo4j.kernel.EmbeddedGraphDatabase 類的對象,并指定數據庫文件的存儲目錄即可。在使用 Neo4j 數據庫時,進行修改的操作一般需要包含在一個事務中來進行處理。通過 GraphDatabaseService 接口的 createNode 方法可以創(chuàng)建新的節(jié)點。Node 接口的 createRelationshipTo 方法可以在當前節(jié)點和另外一個節(jié)點之間創(chuàng)建關系。
另外一個與節(jié)點和關系相關的概念是路徑。路徑有一個起始節(jié)點,接著的是若干個成對的關系和節(jié)點對象。路徑是在對象圖上進行查詢或遍歷的結果。Neo4j 中使用 org.neo4j.graphdb.Path 接口來表示路徑。Path 接口提供了對其中包含的節(jié)點和關系進行處理的一些操作,包括 startNode 和 endNode 方法來獲取起始和結束節(jié)點,以及 nodes 和 relationships 方法來獲取遍歷所有節(jié)點和關系的 Iterable 接口的實現(xiàn)。關于圖上的查詢和遍歷,在下面小節(jié)中會進行具體的介紹。
使用索引
當 Neo4j 數據庫中包含的節(jié)點比較多時,要快速查找滿足條件的節(jié)點會比較困難。Neo4j 提供了對節(jié)點進行索引的能力,可以根據索引值快速地找到相應的節(jié)點。清單 2?給出了索引的基本用法。
清單 2. 索引的使用示例
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public void useIndex() { ???GraphDatabaseService db = new EmbeddedGraphDatabase("music"); ???Index<Node> index = db.index().forNodes("nodes"); ???Transaction tx = db.beginTx(); ???try { ???????Node node1 = db.createNode(); ???????String name = "歌手 1"; ???????node1.setProperty("name", name); ???????index.add(node1, "name", name); ???????node1.setProperty("gender", "男"); ???????tx.success(); ???} finally { ???????tx.finish(); ???} ???Object result = index.get("name", "歌手 1").getSingle() .getProperty("gender"); ???System.out.println(result); // 輸出為“男” } |
在?清單 2?中,通過 GraphDatabaseService 接口的 index 方法可以得到管理索引的 org.neo4j.graphdb.index.IndexManager 接口的實現(xiàn)對象。Neo4j 支持對節(jié)點和關系進行索引。通過 IndexManager 接口的 forNodes 和 forRelationships 方法可以分別得到節(jié)點和關系上的索引。索引通過 org.neo4j.graphdb.index.Index 接口來表示,其中的 add 方法用來把節(jié)點或關系添加到索引中,get 方法用來根據給定值在索引中進行查找。
圖的遍歷
在圖上進行的最實用的操作是圖的遍歷。通過遍歷操作,可以獲取到與圖中節(jié)點之間的關系相關的信息。Neo4j 支持非常復雜的圖的遍歷操作。在進行遍歷之前,需要對遍歷的方式進行描述。遍歷的方式的描述信息由下列幾個要素組成。
- 遍歷的路徑:通常用關系的類型和方向來表示。
- 遍歷的順序:常見的遍歷順序有深度優(yōu)先和廣度優(yōu)先兩種。
- 遍歷的唯一性:可以指定在整個遍歷中是否允許經過重復的節(jié)點、關系或路徑。
- 遍歷過程的決策器:用來在遍歷過程中判斷是否繼續(xù)進行遍歷,以及選擇遍歷過程的返回結果。
- 起始節(jié)點:遍歷過程的起點。
Neo4j 中遍歷方式的描述信息由 org.neo4j.graphdb.traversal.TraversalDescription 接口來表示。通過 TraversalDescription 接口的方法可以描述上面介紹的遍歷過程的不同要素。類 org.neo4j.kernel.Traversal 提供了一系列的工廠方法用來創(chuàng)建不同的 TraversalDescription 接口的實現(xiàn)。清單 3?中給出了進行遍歷的示例。
清單 3. 遍歷操作的示例
| 1 2 3 4 5 6 7 8 9 10 | TraversalDescription td = Traversal.description() ???.relationships(RelationshipTypes.PUBLISH) ???.relationships(RelationshipTypes.CONTAIN) ???.depthFirst() ???.evaluator(Evaluators.pruneWhereLastRelationshipTypeIs(RelationshipTypes.CONTAIN)); Node node = index.get("name", "歌手 1").getSingle(); Traverser traverser = td.traverse(node); for (Path path : traverser) { ???System.out.println(path.endNode().getProperty("name")); } |
在?清單 3?中,首先通過 Traversal 類的 description 方法創(chuàng)建了一個默認的遍歷描述對象。通過 TraversalDescription 接口的 relationships 方法可以設置遍歷時允許經過的關系的類型,而 depthFirst 方法用來設置使用深度優(yōu)先的遍歷方式。比較復雜的是表示遍歷過程的決策器的 evaluator 方法。該方法的參數是 org.neo4j.graphdb.traversal.Evaluator 接口的實現(xiàn)對象。Evalulator 接口只有一個方法 evaluate。evaluate 方法的參數是 Path 接口的實現(xiàn)對象,表示當前的遍歷路徑,而 evaluate 方法的返回值是枚舉類型 org.neo4j.graphdb.traversal.Evaluation,表示不同的處理策略。處理策略由兩個方面組成:第一個方面為是否包含當前節(jié)點,第二個方面為是否繼續(xù)進行遍歷。Evalulator 接口的實現(xiàn)者需要根據遍歷時的當前路徑,做出相應的決策,返回適當的 Evaluation 類型的值。類 org.neo4j.graphdb.traversal.Evaluators 提供了一些實用的方法來創(chuàng)建常用的 Evalulator 接口的實現(xiàn)對象。清單 3 中使用了 Evaluators 類的 pruneWhereLastRelationshipTypeIs 方法。該方法返回的 Evalulator 接口的實現(xiàn)對象會根據遍歷路徑的最后一個關系的類型來進行判斷,如果關系類型滿足給定的條件,則不再繼續(xù)進行遍歷。
清單 3?中的遍歷操作的作用是查找一個歌手所發(fā)行的所有歌曲。遍歷過程從表示歌手的節(jié)點開始,沿著 RelationshipTypes.PUBLISH 和 RelationshipTypes.CONTAIN 這兩種類型的關系,按照深度優(yōu)先的方式進行遍歷。如果當前遍歷路徑的最后一個關系是 RelationshipTypes.CONTAIN 類型,則說明路徑的最后一個節(jié)點包含的是歌曲信息,可以終止當前的遍歷過程。通過 TraversalDescription 接口的 traverse 方法可以從給定的節(jié)點開始遍歷。遍歷的結果由 org.neo4j.graphdb.traversal.Traverser 接口來表示,可以從該接口中得到包含在結果中的所有路徑。結果中的路徑的終止節(jié)點就是表示歌曲的實體。
Neo4j 實戰(zhàn)開發(fā)
在介紹了 Neo4j 的基本使用方式之后,下面通過具體的案例來說明 Neo4j 的使用。作為一個數據庫,Neo4j 可以很容易地被使用在 Web 應用開發(fā)中,就如同通常使用的 MySQL、SQL Server 和 DB2 等關系數據庫一樣。不同之處在于如何對應用中的數據進行建模,以適應后臺存儲方式的需求。同樣的領域模型,既可以映射為關系數據庫中的 E-R 模型,也可以映射為圖形數據庫中的圖模型。對于某些應用來說,映射為圖模型更為自然,因為領域模型中對象之間的各種關系會形成復雜的圖結構。
本節(jié)中使用的示例是一個簡單的微博應用。在微博應用中,主要有兩種實體,即用戶和消息。用戶之間可以互相關注,形成一個圖結構。用戶發(fā)布不同的微博消息。表示微博消息的實體也是圖中的一部分。從這個角度來說,使用 Neo4j 這樣的圖形數據庫,可以更好地描述該應用的領域模型。
如同使用關系數據庫一樣,在使用 Neo4j 時,既可以使用 Neo4j 自身的 API,也可以使用第三方框架。Spring 框架中的 Spring Data 項目提供了對 Neo4j 的良好支持,可以在應用開發(fā)中來使用。Spring Data 項目把 Neo4j 數據庫中的 CRUD 操作、使用索引和進行圖的遍歷等操作進行了封裝,提供了更加抽象易用的 API,并通過使用注解來減少開發(fā)人員所要編寫的代碼量。示例的代碼都是通過 Spring Data 來使用 Neo4j 數據庫的。下面通過具體的步驟來介紹如何使用 Spring Data 和 Neo4j 數據庫。
開發(fā)環(huán)境
使用 Neo4j 進行開發(fā)時的開發(fā)環(huán)境的配置比較簡單。只需要根據?參考資源中給出的地址,下載 Neo4j 本身的 jar 包以及所依賴的 jar 包,并加到 Java 程序的 CLASSPATH 中就可以了。不過推薦使用 Maven 或 Gradle 這樣的工具來進行 Neo4j 相關依賴的管理。
定義數據存儲模型
前面已經提到了應用中有兩種實體,即用戶和消息。這兩種實體需要定義為對象圖中的節(jié)點。清單 1?中給出的創(chuàng)建實體的方式并不直觀,而且并沒有專門的類來表示實體,后期維護成本比較高。Spring Data 支持在一般的 Java 類上添加注解的方式來聲明 Neo4j 中的節(jié)點。只需要在 Java 類上添加 org.springframework.data.neo4j.annotation.NodeEntity 注解即可,如?清單 4?所示。
清單 4. 使用 NodeEntity 注解聲明節(jié)點類
| 1 2 3 4 5 6 7 8 9 | @NodeEntity public class User { @GraphId Long id; @Indexed String loginName; String displayName; String email; } |
如?清單 4?所示,User 類用來表示用戶,作為圖中的節(jié)點。User 類中的域自動成為節(jié)點的屬性。注解 org.springframework.data.neo4j.annotation.GraphId 表明該屬性作為實體的標識符,只能使用 Long 類型。注解 org.springframework.data.neo4j.annotation.Indexed 表明為屬性添加索引。
節(jié)點之間的關系同樣用注解的方式來聲明,如?清單 5?所示。
清單 5. 使用 RelationshipEntity 注解聲明關系類
| 1 2 3 4 5 6 7 8 9 | @RelationshipEntity(type = "FOLLOW") public class Follow { @StartNode User follower; @EndNode User followed; Date followingDate = new Date(); } |
在?清單 5?中,RelationshipEntity 注解的屬性 type 表示關系的類型,StartNode 和 EndNode 注解則分別表示關系的起始節(jié)點和終止節(jié)點。
在表示實體的類中也可以添加對關聯(lián)的節(jié)點的引用,如?清單 6?中給出的 User 類中的其他域。
清單 6. User 類中對關聯(lián)節(jié)點的引用
| 1 2 3 4 5 6 7 8 | @RelatedTo(type = "FOLLOW", direction = Direction.INCOMING) @Fetch Set<User> followers = new HashSet<User>(); @RelatedTo(type = "FOLLOW", direction = Direction.OUTGOING) @Fetch Set<User> followed = new HashSet<User>(); @RelatedToVia(type = "PUBLISH") Set<Publish> messages = new HashSet<Publish>(); |
如?清單 6?所示,注解 RelatedTo 表示與當前節(jié)點通過某種關系關聯(lián)的節(jié)點。因為關系是有向的,可以通過 RelatedTo 的 direction 屬性來聲明關系的方向。對當前用戶節(jié)點來說,如果 FOLLOW 關系的終止節(jié)點是當前節(jié)點,則說明關系的起始節(jié)點對應的用戶是當前節(jié)點對應的用戶的粉絲,用“direction = Direction.INCOMING”來表示。因此 followers 域表示的是當前用戶的粉絲的集合,而 followed 域表示的是當前用戶所關注的用戶的集合。注解 RelatedToVia 和 RelatedTo 的作用類似,只不過 RelatedToVia 不關心關系的方向,只關心類型。因此 messages 域包含的是當前用戶所發(fā)布的消息的集合。
數據操作
在定義了數據存儲模型之后,需要創(chuàng)建相應的類來對數據進行操作。數據操作的對象是數據模型中的節(jié)點和關系類的實例,所涉及的操作包括常見的 CRUD,即創(chuàng)建、讀取、更新和刪除,還包括通過索引進行的查找和圖上的遍歷操作等。由于這些操作的實現(xiàn)方式都比較類似,Spring Data 對這些操作進行了封裝,提供了簡單的使用接口。Spring Data 所提供的數據操作核心接口是 org.springframework.data.neo4j.repository.GraphRepository。GraphRepository 接口繼承自三個提供不同功能的接口:org.springframework.data.neo4j.repository.CRUDRepository 接口提供 save、delete、findOne 和 findAll 等方法,用來進行基本的 CRUD 操作;org.springframework.data.neo4j.repository.IndexRepository 則提供了 findByPropertyValue、findAllByPropertyValue 和 findAllByQuery 等方法,用來根據索引來查找;org.springframework.data.neo4j.repository.TraversalRepository 則提供了 findAllByTraversal 方法,用來根據 TraversalDescription 接口的描述來進行遍歷操作。
Spring Data 為 GraphRepository 接口提供了默認的實現(xiàn)。在大多數情況下,只需要聲明一個接口繼承自 GraphRepository 接口即可,Spring Data 會在運行時創(chuàng)建相應的實現(xiàn)類的對象。對表示用戶的節(jié)點類 User 進行操作的接口 UserRepository 如?清單 7所示。
清單 7. 操作 User 類的 UserRepository 接口
| 1 2 | public interface UserRepository extends GraphRepository<User> { } |
如?清單 7?所示,UserRepository 接口繼承自 GraphRepository 接口,并通過泛型聲明要操作的是 User 類。對節(jié)點類的操作比較簡單,而對于關系類的操作就相對復雜一些。清單 8?中給出了對發(fā)布關系進行操作的接口 PublishRepository 的實現(xiàn)。
清單 8. 操作 Publish 類的 PublishRepository 接口
| 1 2 3 4 5 6 7 8 9 | public interface PublishRepository extends GraphRepository<Publish> { @Query("start user1=node({0}) " + ???????????" match user1-[:FOLLOW]->user2-[r2:PUBLISH]->followedMessage" + ???????????" return r2") List<Publish> getFollowingUserMessages(User user); @Query("start user=node({0}) match user-[r:PUBLISH]->message return r") List<Publish> getOwnMessages(User user); } |
在?清單 8?中,getFollowingUserMessages 方法用來獲取某個用戶關注的所有其他用戶所發(fā)布的消息。該方法的實現(xiàn)是通過圖上的遍歷操作來完成的。Spring Data 提供了一種簡單的查詢語言來描述遍歷操作。通過在方法上添加 org.springframework.data.neo4j.annotation.Query 注解來聲明所使用的遍歷方式即可。以 getFollowingUserMessages 方法的遍歷聲明為例,“node({0})”表示當前節(jié)點,“start user1=node({0})”表示從當前節(jié)點開始進行遍歷,并用 user1 表示當前節(jié)點。“match”用來表示遍歷時選中的節(jié)點應該滿足的條件。條件“user1-[:FOLLOW]->user2-[r2:PUBLISH]->followedMessage”中,先通過類型為 FOLLOW 的關系找到 user1 所關注的用戶,以 user2 來表示;再通過類型為 PUBLISH 的關系,查找 user2 所發(fā)布的消息?!皉eturn”用來返回遍歷的結果,r2 表示的是類型為 PUBLISH 的關系,與 getFollowingUserMessages 方法的返回值類型 List<Publish> 相對應。
在應用中的使用
在定義了數據操作的接口之后,就可以在應用的服務層代碼中使用這些接口。清單 9?中給出了用戶發(fā)布新微博時的操作方法。
清單 9. 用戶發(fā)布新微博的方法
| 1 2 3 4 5 6 7 8 9 10 | @Autowired UserRepository userRepository; @Transactional public void publish(User user, String content) { Message message = new Message(content); messageRepository.save(message); user.publish(message); userRepository.save(user); } |
如?清單 9?所示,publish 方法用來給用戶 user 發(fā)布內容為 content 的微博。域 userRepository 是 UserRepository 接口的引用,由 Spring IoC 容器在運行時自動注入依賴,該接口的具體實現(xiàn)由 Spring Data 提供。在 publish 方法中,首先創(chuàng)建一個 Message 實體類的對象,表示消息節(jié)點;再通過 save 方法把該節(jié)點保存到數據庫中。User 類的 publish 方法的實現(xiàn)如?清單 10所示,其邏輯是創(chuàng)建一個 Publish 類的實例表示發(fā)布關系,并建立用戶和消息實體之間的關系。最后再更新 user 對象即可。
清單 10. User 類的 publish 方法
| 1 2 3 4 5 6 7 8 | @RelatedToVia(type = "PUBLISH") Set<Publish> messages = new HashSet<Publish>(); public Publish publish(Message message) { Publish publish = new Publish(this, message); this.messages.add(publish); return publish; } |
在創(chuàng)建了相關的服務層類之后,就可以從服務層中暴露出相關的使用 JSON 的 REST 服務,然后在 REST 服務的基礎上創(chuàng)建應用的前端展示界面。界面的實現(xiàn)部分與 Neo4j 并無關系,在這里不再贅述。整個程序基于 Spring 框架來開發(fā)。Spring Data 為 Neo4j 提供了獨立的配置文件名稱空間,可以方便在 Spring 配置文件中對 Neo4j 進行配置。清單 11?給出了與 Neo4j 相關的 Spring 配置文件。
清單 11. Neo4j 的 Spring 配置文件
| 1 2 | <neo4j:config storeDirectory="data/neo-mblog.db" /> <neo4j:repositories base-package="com.chengfu.neomblog.repository" /> |
在?清單 11?中,config 元素用來設置 Neo4j 數據庫的數據保存目錄,repositories 元素用來聲明操作 Neo4j 中的節(jié)點和關系類的 GraphRepository 接口的子接口的包名。Spring Data 會負責在運行時掃描該 Java 包,并為其中包含的接口創(chuàng)建出對應的實現(xiàn)對象。
示例應用的完整代碼存放在 GitHub 上,見?參考資源。
使用 Neo4j 原生 API
如果不使用 Spring Data 提供的 Neo4j 支持,而使用 Neo4j 的原生 API,也是一樣可以進行開發(fā)。只不過由于 Neo4j 的原生 API 的抽象層次較低,使用起來不是很方便。下面以示例應用中用戶發(fā)布微博的場景來展示原生 API 的基本用法,見?清單 12。
清單 12. 使用 Neo4j 原生 API
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public void publish(String username, String message) { ???GraphDatabaseService db = new EmbeddedGraphDatabase("mblog"); ???Index<Node> index = db.index().forNodes("nodes"); ???Node ueserNode = index.get("user-loginName", username).getSingle(); ???if (ueserNode != null){ ???????Transaction tx = db.beginTx(); ???????try { ???????????Node messageNode = db.createNode(); ???????????messageNode.setProperty("message", message); ???????????ueserNode.createRelationshipTo(messageNode, RelationshipTypes.PUBLISH); ???????????tx.success(); ???????} finally { ???????????tx.finish(); ???????} ???} } |
從?清單 12?中可以看出,原生 API 的基本用法是先通過 Neo4j 數據庫的索引找到需要操作的表示用戶的節(jié)點,然后再創(chuàng)建出表示微博消息的節(jié)點,最后在兩個節(jié)點之間建立關系。這些步驟都使用 Neo4j 的基本 API 來完成。
與?清單 10?中使用 Spring Data 的功能相同的方法進行比較,可以發(fā)現(xiàn)使用原生 API 的代碼要復雜不少,而使用 Spring Data 的則簡潔很多。因此,在實際開發(fā)中推薦使用 Spring Data。
小結
關系數據庫在很長一段時間都是大多數應用采用的數據存儲方式的首要選擇。隨著技術的發(fā)展,越來越多的 NoSQL 數據庫開始流行起來。對于應用開發(fā)人員來說,不應該總是盲目使用關系數據庫,而是要根據應用本身的特點,選用最合適的存儲方式。Neo4j 數據庫以“圖”作為數據之間關系的描述方式,非常適合于使用在數據本身就以圖結構來組織的應用中。本文對 Neo4j 數據庫的使用做了詳細的介紹,可以幫助開發(fā)人員了解和使用 Neo4j 數據庫。
總結
- 上一篇: ABAP在ALV工具栏显示一个计时器
- 下一篇: ABAP数字类型合法性检查函数NUMER