通過Spring Data Neo4J操作您的圖形數據庫

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

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

?

添加Spring Data Neo4J的支持

  如果想要使用Spring Data Neo4J,我們要做的第一步便是在項目中添加對Spring Data Neo4J的支持。如果您是使用Maven對項目進行管理,那么您首先要在項目中添加使用Spring Data Neo4J所需要的各個依賴項:

 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運行時所需要使用的配置:

 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文件夾下。

  而為了能讓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

公眾號一定幫忙別標成原創,因為協調起來太麻煩了。。。

轉載于:https://www.cnblogs.com/loveis715/p/5425790.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/255519.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/255519.shtml
英文地址,請注明出處:http://en.pswp.cn/news/255519.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

圖像金字塔

圖像金字塔被廣泛用于各種視覺應用中。圖像金字塔是一個圖像集合&#xff0c;集合中所有的圖像都源于同一個原始圖像&#xff0c;而且是通過對原始圖像連續降采樣活得&#xff0c;直到達到某個中止條件才停止降采樣。&#xff08;當然&#xff0c;降為一個像素肯定是中止條件。…

python使用git進行版本控制-分支管理

1、遠程克隆 最好的方式是先創建遠程庫&#xff0c;然后&#xff0c;從遠程庫克隆&#xff1a; 首先在github上創建一個新的倉庫&#xff0c;名字叫gitskills 我們勾選Initialize this repository with a README&#xff0c;這樣GitHub會自動為我們創建一個README.md文件。 下一…

【python數字信號處理】——Z變換

目錄 一、公式 二、代碼 三、結果 一、公式 頻域變量&#xff1a;z 時域變量&#xff1a;n 常見序列的Z變換&#xff1a;信號與系統復習歸納&#xff08;十一&#xff09;&#xff1a;Z變換例題_百把人的博客-CSDN博客_z變換例題基于東南大學陳從顏譯《信號、系統和變換》和…

九宮格拼圖 支持44 55等

代碼下載轉載于:https://www.cnblogs.com/ygcool/p/5395343.html

144. Binary Tree Preorder Traversal

Given a binary tree, return the preorder traversal of its nodes values. For example:Given binary tree {1,#,2,3}, 1\2/3return [1,2,3]. 該題是對樹做前序遍歷 下面分別是遞歸&#xff0c;非遞歸&#xff0c;分治三種思路的解題結果 #遞歸寫法 class Solution(object):d…

一體化點焊機將要取代分體式焊鉗在汽車制造生產線上的使用

目前大多數汽車制造廠及相關配套鈑金件廠家選用的是懸掛式點焊機及分體式焊鉗&#xff0c;從焊接變壓器的功率參數看&#xff0c;約70 % 為160KVA 的&#xff0c;約30 % 為200 kVA 的。原因主要有兩方面&#xff0c;一是新材料如鍍鋅鋼板、高強度鋼板、鋁合金板的應用&#xff…

【python數字信號處理】——線性卷積

目錄 一、公式概念 二、代碼 1、numpy庫 2、自定義打印出每一步結果 三、結果 一、公式概念 線性卷積_百度百科線性卷積(linear convolution) 在時域描述線性系統輸入和輸出之間關系的一種運算。這種運算在線性系統分析和信號處理中應用很多&#xff0c;通常簡稱卷積。中文…

activiti web流程設計器 整合視頻 教程 SSM和獨立部署的方式

本視頻為activiti工作流的web流程設計器整合視頻教程整合Acitiviti在線流程設計器(Activiti-Modeler 5.21.0 官方流程設計器&#xff09;本視頻共講了兩種整合方式1. 流程設計器和其它工作流項目分開部署的方式2. 流程設計器和SSM框架項目整合在一起的方式視頻大小 1.13 GB ~【…

移動端判斷橫屏豎屏

1. CSS判斷橫屏豎屏 寫在同一個CSS中 media screen and (orientation: portrait) {   /*豎屏 css*/} media screen and (orientation: landscape) and (min-width:450px){   /*橫屏 css*/}分開寫在2個CSS 豎屏<link rel"stylesheet" media"all and (orie…

第五章 - 圖像形態學 - 基于圖像金字塔的圖像分割(cvPyrSegmentation)

本例程涉及到幾個數據結構及方法&#xff0c;CvMemStorage、cvPyrSegmentation()、CvConnectedComp、cvGetSeqElem(). CvMemStorage CvMemStorage Growing memory storage typedef struct CvMemStorage { struct CvMemBlock* bottom;/* first allocated block */ struct CvM…

泛型參數轉換的問題

泛型不同參數類型生成的對象是相互獨立的。 //如 Tuple<string> ts; Tuple<object> to; //ts to 是兩個類型的對象。很多時候&#xff0c;我們希望實現 to ts 這種操作&#xff0c;為什么&#xff1f;因為看上去它應該如此。 為了達到這個目的&#xff0c;就要解決…

【python數字信號處理】——循環卷積(也叫圓圈卷積)

目錄 一、公式 二、代碼 方法一:遍歷 方法二:利用卷積定理 一、公式

UI-UIScrollView

- (void)viewDidLoad { [super viewDidLoad]; scrollView [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)]; scrollView.backgroundColor [UIColor redColor]; // 是否支持滑動最頂端 // scrollView.scrollsToTop NO; scrollView.delegate self; // 設…

[COCI2015]ZGODAN

題目大意&#xff1a;   給你一個數$n(n\leq10^1000)$&#xff0c;定義一個數是“美麗數”當且僅當這個數各個數位上的數奇偶性不同。   求最接近$n$的“美麗數”&#xff0c;若有多個&#xff0c;則依次輸出。 思路&#xff1a;   貪心高精度。   首先找出$n$的第一個…

OpenCV學習筆記(三)——Mat,圖像的新容器

自從版本2.0&#xff0c;OpenCV采用了新的數據結構&#xff0c;用Mat類結構取代了之前用extended C寫的cvMat和lplImage&#xff0c;更加好用啦&#xff0c;最大的好處就是更加方便的進行內存管理&#xff0c;對寫更大的程序是很好的消息。 需要注意的幾點&#xff1a;1. Mat的…

jq實現事件委托

事件委托首 頁產品展示公司簡介關于我們聯系我們轉載于:https://www.cnblogs.com/haley168/p/eventTarget.html

【python數字信號處理】——scipy庫設計濾波器(IIR為例)、繪制濾波器頻譜響應、IIR濾波器濾波、讀寫wav音頻文件

目錄 一、參考文獻 1、scipy接口 2、scipy庫介紹+IIR濾波器設計(含GUI)+繪制頻譜響應

關于SQL查詢效率,100w數據,查詢只要1秒

原文:關于SQL查詢效率&#xff0c;100w數據&#xff0c;查詢只要1秒1.關于SQL查詢效率&#xff0c;100w數據&#xff0c;查詢只要1秒&#xff0c;與您分享:機器情況p4: 2.4內存: 1 Gos: windows 2003數據庫: ms sql server 2000目的: 查詢性能測試,比較兩種查詢的性能SQL查詢效…

OpenCV學習筆記(五十四)——概述FaceRecognizer人臉識別類contrib

在最新版的2.4.2中&#xff0c;文檔的更新也是一大亮點&#xff0c;refrence manual擴充了200多頁的內容&#xff0c;添加了contrib部分的文檔。contrib就是指OpenCV中新添加的模塊&#xff0c;但又不是很穩定&#xff0c;可以認為是一個雛形的部分。這次結合refman的閱讀&…

【調試】Linux下超強內存檢測工具Valgrind

【調試】Linux下超強內存檢測工具Valgrind 內容簡介 Valgrind是什么&#xff1f;Valgrind的使用Valgrind詳細教程1. Valgrind是什么&#xff1f; Valgrind是一套Linux下&#xff0c;開放源代碼&#xff08;GPLV2&#xff09;的仿真調試工具的集合。Valgrind由內核&#xff08;c…