經過Spring Data Neo4J操做您的圖形數據庫

  在前面的一篇文章《圖形數據庫Neo4J簡介》中,咱們已經對其內部所使用的各類機制進行了簡單地介紹。而在咱們嘗試對Neo4J進行大版本升級時,我發現網絡上並無任何成型的樣例代碼以及簡介,而其自身的文檔也對如何使用Spring Data Neo4J介紹得語焉不詳。所以在本文中,咱們就將簡單地介紹如何使用Spring Data Neo4J。html

  本文中所使用的全部的代碼都是基於Spring Data Neo4J 4.1.1的。我已經將這些代碼放置在https://github.com/loveis715/Spring-Neo4J中。讀者能夠自行下載並查看其所包含的各次更改。該樣例項目內部是按照版本進行組織的。也就是說,一旦我發現其它後續版本再次出現大範圍的API改動,那麼我會建立一個新版本文件夾,並在其中添加相應的代碼。git

 

添加Spring Data Neo4J的支持github

  若是想要使用Spring Data Neo4J,咱們要作的第一步即是在項目中添加對Spring Data Neo4J的支持。若是您是使用Maven對項目進行管理,那麼您首先要在項目中添加使用Spring Data Neo4J所須要的各個依賴項:spring

 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>

  首先來讓咱們來看看依賴項neo4j-ogm-embedded-driver。其主要用來提供對內嵌Driver的支持。Spring Data Neo4J主要支持兩類Driver:內嵌Driver以及Http Driver。內嵌Driver會直接鏈接本地圖形數據庫,所以較適合開發環境;而Http Driver則會經過Http與圖形數據庫實例溝通,所以更加適合生產環境。數據庫

  第二個依賴項spring-test以及第三個依賴項JUnit則添加了基於Spring Framework的測試功能的支持。這裏咱們所使用的Spring Framework的版本是4.2.5.RELEASE,也是與Spring Data Neo4J所兼容的最低版本。編程

  而最後一個依賴項spring-data-neo4j也沒必要多說。其是Spring Data Neo4J所對應的依賴項。網絡

  添加完這些依賴項以後,咱們就須要對Spring Data Neo4J進行配置了。在以前的版本中,咱們只須要經過Spring的配置文件標明圖形數據庫的地址以及圖形數據庫數據類型所在的包便可。而Spring Data Neo4J 4.1.1已經再也不支持這種配置方式了,甚至用來處理http://www.springframework.org/schema/data/neo4j這個XML命名空間的Neo4jNamespaceHandler類都已經被移除。做爲替代,咱們須要從Neo4jConfiguration類派生,以指定Spring Data Neo4J運行時所須要使用的配置:session

 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 }

  上面的代碼主要指出了三個配置項:Spring Data Neo4J所須要使用的各個Repository主要存在於com.ambergarden.samples.neo4j.repositories包中,而其所操做的各個數據類型則主要存在於com.ambergarden.samples.neo4j.entities包中。同時咱們還標明瞭咱們將使用內嵌Driver,並將數據暫時存儲在D:\neo4j\graph.db文件夾下。ide

  而爲了能讓Spring可以探測到該配置類,咱們首先須要在該類型之上添加@Configuration標記,而後還須要在Spring的配置文件中經過component-scan元素來讓Spring Framework搜索配置文件所在的包com.ambergarden.samples.neo4j:單元測試

1 <context:component-scan base-package="com.ambergarden.samples.neo4j" />

  至此爲止,咱們已經完成了對Spring Data Neo4J的配置。那麼好,讓咱們建立一個簡單的測試類來驗證這些配置的正確性:

 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 }

  接下來,咱們就須要添加對該類型進行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能正確地運行這些單元測試,那麼恭喜,您已經成功地配置了Spring Data Neo4J。

 

定義數據實體

  在確認了咱們爲使用Spring Data Neo4J所進行的項目配置不存在問題以後,咱們就須要開始嘗試定義操做Neo4J所需的實體了。若是須要將一個類型聲明爲Neo4J實體,那麼咱們就須要在相應的類型定義上使用@NodeEntity標記:

1 @NodeEntity
2 public class Person {
3    ……
4 }

  除此以外,咱們還須要經過@GraphId標記標明用來記錄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 }

  因爲該域是如此經常使用,所以咱們經常會將其移到基類實現中,並根據該域的值來重寫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實體只須要從該類派生就能獲得equals()和hashCode()的支持了。至於如何正確地實現equals()以及如何正確地實現hashCode(),網絡上的講解不少,這裏就再也不贅述。感興趣的讀者能夠自行查看GitHub上的示例代碼。

  好,有了實體,下一步要作的就是定義實體之間的關係了。先讓咱們看一個如何建立簡單關係的示例:

 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類之間建立簡單的關係。能夠看到,咱們只須要建立對關係另外一端實例的引用,並經過@Relationship標記在這些引用之上標明關係的名稱便可。若是一個關係是有向的,例如READER_OF關係須要被解讀爲Person p is READER_OF Book b,那麼咱們就須要在關係的兩端標明關係的方向。在上面的示例中,READER_OF關係的方向即是由Person指向Book。固然,咱們也能夠經過UNDIRECTED來標示一個關係是沒有方向的。

  固然,咱們是爲了方便纔在Book中添加了指向Person實例的集合。若是在您的Book實體中添加這麼個域並不會爲您帶來方便,那麼您徹底能夠省略該域。並且該作法還會在必定程度上簡化您編寫代碼的複雜度。讓咱們來看下面的一段用來在Person實例和Book實例之間創建關係的示例代碼(詳見測試代碼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實例添加一個對Book類實例的引用須要這麼多行代碼?答案就是,若是咱們只更新了關係的一端卻沒有更新關係的另外一端,那麼關係兩端所記錄的關係就會出現不一致,進而致使Neo4J根本沒法判斷應該根據哪一端所記錄的數據對數據庫進行操做。您說是不?

  往更深一步說,圖形數據庫中一個很是容易犯錯的地方就是對圖的修改會致使圖處於一個非一致狀態。在這種狀況下,對這些數據的保存將可能致使圖自己處於一個非指望的狀態,並逐漸發展爲混亂狀態。例如在刪除一個實例時沒有維護圖中其它結點對它的引用,那麼該刪除操做就可能會致使這些結點中所記錄的引用是非法的,甚至使得整個數據庫沒法加載。您別不信,咱們真遇到過。

  因此說,圖形數據庫編程中,您必定要在每一個對圖的操做中保證圖是處於一個合法的一致狀態。這也即是爲什麼咱們經常在關係的兩端都記錄關係的緣由:一旦其中一個結點有變,咱們能夠快速找到對它的引用,並對該引用進行維護。

  您可能還有一個問題,那就是,圖形數據庫不是用來記錄富關係的麼?那咱們應該如何在關係中記錄額外的數據呢?此時咱們就須要經過@RelationshipEntity標記來定義一個富關係,並進而在各個實體定義中使用該關係:

 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 }

  此時在咱們的實體定義中所記錄的再也不是富關係另外一端的實體集合,而是富關係自己。

 

  相信通過這麼一篇簡短的介紹,您已經瞭解瞭如何使用Spring Data Neo4J來操做數據庫了。若是您感興趣,能夠下載我放置在https://github.com/loveis715/Spring-Neo4J中的示例代碼。

 

轉載請註明原文地址並標明轉載:http://www.cnblogs.com/loveis715/p/5425790.html

商業轉載請事先與我聯繫:silverfox715@sina.com

公衆號必定幫忙別標成原創,由於協調起來太麻煩了。。。

相關文章
相關標籤/搜索