javascript
通过Spring Data Neo4J操作您的图形数据库
在前面的一篇文章《圖形數(shù)據(jù)庫Neo4J簡介》中,我們已經(jīng)對其內(nèi)部所使用的各種機(jī)制進(jìn)行了簡單地介紹。而在我們嘗試對Neo4J進(jìn)行大版本升級時,我發(fā)現(xiàn)網(wǎng)絡(luò)上并沒有任何成型的樣例代碼以及簡介,而其自身的文檔也對如何使用Spring Data Neo4J介紹得語焉不詳。因此在本文中,我們就將簡單地介紹如何使用Spring Data Neo4J。
本文中所使用的所有的代碼都是基于Spring Data Neo4J 4.1.1的。我已經(jīng)將這些代碼放置在https://github.com/loveis715/Spring-Neo4J中。讀者可以自行下載并查看其所包含的各次更改。該樣例項(xiàng)目內(nèi)部是按照版本進(jìn)行組織的。也就是說,一旦我發(fā)現(xiàn)其它后續(xù)版本再次出現(xiàn)大范圍的API改動,那么我會創(chuàng)建一個新版本文件夾,并在其中添加相應(yīng)的代碼。
?
添加Spring Data Neo4J的支持
如果想要使用Spring Data Neo4J,我們要做的第一步便是在項(xiàng)目中添加對Spring Data Neo4J的支持。如果您是使用Maven對項(xiàng)目進(jìn)行管理,那么您首先要在項(xiàng)目中添加使用Spring Data Neo4J所需要的各個依賴項(xiàng):
1 <dependency> 2 <groupId>org.neo4j</groupId> 3 <artifactId>neo4j-ogm-embedded-driver</artifactId> 4 <version>2.0.1</version> 5 </dependency> 6 <dependency> 7 <groupId>org.springframework</groupId> 8 <artifactId>spring-test</artifactId> 9 <version>4.2.5.RELEASE</version> 10 </dependency> 11 <dependency> 12 <groupId>junit</groupId> 13 <artifactId>junit</artifactId> 14 <version>4.9</version> 15 </dependency> 16 <dependency> 17 <groupId>org.springframework.data</groupId> 18 <artifactId>spring-data-neo4j</artifactId> 19 <version>4.1.1.RELEASE</version> 20 </dependency>首先來讓我們來看看依賴項(xiàng)neo4j-ogm-embedded-driver。其主要用來提供對內(nèi)嵌Driver的支持。Spring Data Neo4J主要支持兩類Driver:內(nèi)嵌Driver以及Http Driver。內(nèi)嵌Driver會直接連接本地圖形數(shù)據(jù)庫,因此較適合開發(fā)環(huán)境;而Http Driver則會通過Http與圖形數(shù)據(jù)庫實(shí)例溝通,因此更加適合生產(chǎn)環(huán)境。
第二個依賴項(xiàng)spring-test以及第三個依賴項(xiàng)JUnit則添加了基于Spring Framework的測試功能的支持。這里我們所使用的Spring Framework的版本是4.2.5.RELEASE,也是與Spring Data Neo4J所兼容的最低版本。
而最后一個依賴項(xiàng)spring-data-neo4j也不必多說。其是Spring Data Neo4J所對應(yīng)的依賴項(xiàng)。
添加完這些依賴項(xiàng)之后,我們就需要對Spring Data Neo4J進(jìn)行配置了。在之前的版本中,我們只需要通過Spring的配置文件標(biāo)明圖形數(shù)據(jù)庫的地址以及圖形數(shù)據(jù)庫數(shù)據(jù)類型所在的包即可。而Spring Data Neo4J 4.1.1已經(jīng)不再支持這種配置方式了,甚至用來處理http://www.springframework.org/schema/data/neo4j這個XML命名空間的Neo4jNamespaceHandler類都已經(jīng)被移除。作為替代,我們需要從Neo4jConfiguration類派生,以指定Spring Data Neo4J運(yùn)行時所需要使用的配置:
1 @Configuration 2 @EnableNeo4jRepositories(basePackages = "com.ambergarden.samples.neo4j.repositories") 3 @EnableTransactionManagement 4 public class GraphDBConfiguration extends Neo4jConfiguration { 5 6 @Bean 7 public org.neo4j.ogm.config.Configuration getConfiguration() { 8 org.neo4j.ogm.config.Configuration config = 9 new org.neo4j.ogm.config.Configuration(); 10 // TODO: Temporary uses the embedded driver. We need to switch to http 11 // driver. Then we can horizontally scale neo4j 12 config.driverConfiguration() 13 .setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver") 14 .setURI("file:/D:/neo4j/graph.db/"); 15 return config; 16 } 17 18 @Override 19 @Bean 20 public SessionFactory getSessionFactory() { 21 // Return the session factory which also includes the persistent entities 22 return new SessionFactory(getConfiguration(), "com.ambergarden.samples.neo4j.entities"); 23 } 24 }上面的代碼主要指出了三個配置項(xiàng):Spring Data Neo4J所需要使用的各個Repository主要存在于com.ambergarden.samples.neo4j.repositories包中,而其所操作的各個數(shù)據(jù)類型則主要存在于com.ambergarden.samples.neo4j.entities包中。同時我們還標(biāo)明了我們將使用內(nèi)嵌Driver,并將數(shù)據(jù)暫時存儲在D:\neo4j\graph.db文件夾下。
而為了能讓Spring能夠探測到該配置類,我們首先需要在該類型之上添加@Configuration標(biāo)記,然后還需要在Spring的配置文件中通過component-scan元素來讓Spring Framework搜索配置文件所在的包c(diǎn)om.ambergarden.samples.neo4j:
1 <context:component-scan base-package="com.ambergarden.samples.neo4j" />至此為止,我們已經(jīng)完成了對Spring Data Neo4J的配置。那么好,讓我們創(chuàng)建一個簡單的測試類來驗(yàn)證這些配置的正確性:
1 @NodeEntity 2 public class Person { 3 @GraphId 4 private Long id; 5 6 public Long getId() { 7 return id; 8 } 9 10 public void setId(Long id) { 11 this.id = id; 12 } 13 }接下來,我們就需要添加對該類型進(jìn)行CRUD的Repository:
1 public interface PersonRepository extends GraphRepository<Person> { 2 }最后,編寫一小段測試代碼來看看這些類型是否能夠正常工作:
1 @RunWith(SpringJUnit4ClassRunner.class) 2 @ContextConfiguration({ "classpath*:/spring/dal-test-context.xml" }) 3 public class PersonRepositoryTest { 4 @Autowired 5 private PersonRepository personRepository; 6 7 @Test 8 public void testCRUDPerson() { 9 Person person = new Person(); 10 person = personRepository.save(person); 11 assertNotNull(person); 12 assertNotNull(person.getId()); 13 14 Long personId = person.getId(); 15 personRepository.delete(person); 16 person = personRepository.findOne(personId); 17 assertNull(person); 18 } 19 }如果您的Eclipse能正確地運(yùn)行這些單元測試,那么恭喜,您已經(jīng)成功地配置了Spring Data Neo4J。
?
定義數(shù)據(jù)實(shí)體
在確認(rèn)了我們?yōu)槭褂肧pring Data Neo4J所進(jìn)行的項(xiàng)目配置不存在問題之后,我們就需要開始嘗試定義操作Neo4J所需的實(shí)體了。如果需要將一個類型聲明為Neo4J實(shí)體,那么我們就需要在相應(yīng)的類型定義上使用@NodeEntity標(biāo)記:
1 @NodeEntity 2 public class Person { 3 …… 4 }除此之外,我們還需要通過@GraphId標(biāo)記標(biāo)明用來記錄ID的屬性:
1 @NodeEntity 2 public class Person { 3 @GraphId 4 private Long id; 5 6 public Long getId() { 7 return id; 8 } 9 10 public void setId(Long id) { 11 this.id = id; 12 } 13 }由于該域是如此常用,因此我們常常會將其移到基類實(shí)現(xiàn)中,并根據(jù)該域的值來重寫hashCode()和equals()方法:
1 public abstract class AbstractEntity { 2 3 @GraphId 4 private Long id; 5 …… 6 7 @Override 8 public boolean equals(Object obj) { 9 …… 10 } 11 12 @Override 13 public int hashCode() { 14 …… 15 } 16 }此時,所有的Neo4J實(shí)體只需要從該類派生就能得到equals()和hashCode()的支持了。至于如何正確地實(shí)現(xiàn)equals()以及如何正確地實(shí)現(xiàn)hashCode(),網(wǎng)絡(luò)上的講解很多,這里就不再贅述。感興趣的讀者可以自行查看GitHub上的示例代碼。
好,有了實(shí)體,下一步要做的就是定義實(shí)體之間的關(guān)系了。先讓我們看一個如何創(chuàng)建簡單關(guān)系的示例:
1 @NodeEntity 2 public class Person extends NamedEntity { 3 @Relationship(type="READER_OF") 4 private Set<Book> books; 5 …… 6 } 7 8 @NodeEntity 9 public class Book extends DescriptiveEntity { 10 @Relationship(type="READER_OF", direction=Relationship.INCOMING) 11 private Set<Person> readers; 12 …… 13 }上面的代碼展示了如何在Person類和Book類之間創(chuàng)建簡單的關(guān)系。可以看到,我們只需要創(chuàng)建對關(guān)系另一端實(shí)例的引用,并通過@Relationship標(biāo)記在這些引用之上標(biāo)明關(guān)系的名稱即可。如果一個關(guān)系是有向的,例如READER_OF關(guān)系需要被解讀為Person p is READER_OF Book b,那么我們就需要在關(guān)系的兩端標(biāo)明關(guān)系的方向。在上面的示例中,READER_OF關(guān)系的方向便是由Person指向Book。當(dāng)然,我們也可以通過UNDIRECTED來標(biāo)示一個關(guān)系是沒有方向的。
當(dāng)然,我們是為了方便才在Book中添加了指向Person實(shí)例的集合。如果在您的Book實(shí)體中添加這么個域并不會為您帶來方便,那么您完全可以省略該域。而且該做法還會在一定程度上簡化您編寫代碼的復(fù)雜度。讓我們來看下面的一段用來在Person實(shí)例和Book實(shí)例之間建立關(guān)系的示例代碼(詳見測試代碼BookRepositoryTest.testCRUDRelationships()):
1 @Test 2 public void testCRUDRelationships() { 3 …… 4 // Test add readers 5 Book book2 = new Book(); 6 book2.setName(TEST_BOOK_NAME_2); 7 book2 = bookRepository.save(book2); 8 9 readers = new HashSet<Person>(); 10 readers.add(person1); 11 person1.getBooks().add(book2); 12 book2.setReaders(readers); 13 book2 = bookRepository.save(book2); 14 …… 15 }您可能會問:為什么向Person實(shí)例添加一個對Book類實(shí)例的引用需要這么多行代碼?答案就是,如果我們只更新了關(guān)系的一端卻沒有更新關(guān)系的另一端,那么關(guān)系兩端所記錄的關(guān)系就會出現(xiàn)不一致,進(jìn)而導(dǎo)致Neo4J根本無法判斷應(yīng)該根據(jù)哪一端所記錄的數(shù)據(jù)對數(shù)據(jù)庫進(jìn)行操作。您說是不?
往更深一步說,圖形數(shù)據(jù)庫中一個非常容易犯錯的地方就是對圖的修改會導(dǎo)致圖處于一個非一致狀態(tài)。在這種情況下,對這些數(shù)據(jù)的保存將可能導(dǎo)致圖本身處于一個非期望的狀態(tài),并逐漸發(fā)展為混亂狀態(tài)。例如在刪除一個實(shí)例時沒有維護(hù)圖中其它結(jié)點(diǎn)對它的引用,那么該刪除操作就可能會導(dǎo)致這些結(jié)點(diǎn)中所記錄的引用是非法的,甚至使得整個數(shù)據(jù)庫無法加載。您別不信,我們真遇到過。
所以說,圖形數(shù)據(jù)庫編程中,您一定要在每個對圖的操作中保證圖是處于一個合法的一致狀態(tài)。這也便是為何我們常常在關(guān)系的兩端都記錄關(guān)系的原因:一旦其中一個結(jié)點(diǎn)有變,我們可以快速找到對它的引用,并對該引用進(jìn)行維護(hù)。
您可能還有一個問題,那就是,圖形數(shù)據(jù)庫不是用來記錄富關(guān)系的么?那我們應(yīng)該如何在關(guān)系中記錄額外的數(shù)據(jù)呢?此時我們就需要通過@RelationshipEntity標(biāo)記來定義一個富關(guān)系,并進(jìn)而在各個實(shí)體定義中使用該關(guān)系:
1 @RelationshipEntity(type="WRITER_OF") 2 public class WriterOf extends AbstractEntity { 3 @StartNode 4 private Person writer; 5 6 @EndNode 7 private Book book; 8 9 private Date startDate; 10 private Date endDate; 11 …… 12 } 13 14 @NodeEntity 15 public class Person extends NamedEntity { 16 @Relationship(type="WRITER_OF") 17 private Set<WriterOf> writings; 18 19 @Relationship(type="READER_OF") 20 private Set<Book> books; 21 …… 22 }此時在我們的實(shí)體定義中所記錄的不再是富關(guān)系另一端的實(shí)體集合,而是富關(guān)系本身。
?
相信經(jīng)過這么一篇簡短的介紹,您已經(jīng)了解了如何使用Spring Data Neo4J來操作數(shù)據(jù)庫了。如果您感興趣,可以下載我放置在https://github.com/loveis715/Spring-Neo4J中的示例代碼。
?
轉(zhuǎn)載請注明原文地址并標(biāo)明轉(zhuǎn)載:http://www.cnblogs.com/loveis715/p/5425790.html
商業(yè)轉(zhuǎn)載請事先與我聯(lián)系:silverfox715@sina.com
公眾號一定幫忙別標(biāo)成原創(chuàng),因?yàn)閰f(xié)調(diào)起來太麻煩了。。。
轉(zhuǎn)載于:https://www.cnblogs.com/loveis715/p/5425790.html
總結(jié)
以上是生活随笔為你收集整理的通过Spring Data Neo4J操作您的图形数据库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广发犀利卡额度多少?额度高吗?
- 下一篇: JSP内置对象详解