通过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所需要的各个依赖项:
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>4.1.1.RELEASE</version>
</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运行时所需要使用的配置:
@Configuration
@EnableNeo4jRepositories(basePackages = "com.ambergarden.samples.neo4j.repositories")
@EnableTransactionManagement
public class GraphDBConfiguration extends Neo4jConfiguration { @Bean
public org.neo4j.ogm.config.Configuration getConfiguration() {
org.neo4j.ogm.config.Configuration config =
new org.neo4j.ogm.config.Configuration();
// TODO: Temporary uses the embedded driver. We need to switch to http
// driver. Then we can horizontally scale neo4j
config.driverConfiguration()
.setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver")
.setURI("file:/D:/neo4j/graph.db/");
return config;
} @Override
@Bean
public SessionFactory getSessionFactory() {
// Return the session factory which also includes the persistent entities
return new SessionFactory(getConfiguration(), "com.ambergarden.samples.neo4j.entities");
}
}
上面的代码主要指出了三个配置项: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:
<context:component-scan base-package="com.ambergarden.samples.neo4j" />
至此为止,我们已经完成了对Spring Data Neo4J的配置。那么好,让我们创建一个简单的测试类来验证这些配置的正确性:
@NodeEntity
public class Person {
@GraphId
private Long id; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
}
}
接下来,我们就需要添加对该类型进行CRUD的Repository:
public interface PersonRepository extends GraphRepository<Person> {
}
最后,编写一小段测试代码来看看这些类型是否能够正常工作:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath*:/spring/dal-test-context.xml" })
public class PersonRepositoryTest {
@Autowired
private PersonRepository personRepository; @Test
public void testCRUDPerson() {
Person person = new Person();
person = personRepository.save(person);
assertNotNull(person);
assertNotNull(person.getId()); Long personId = person.getId();
personRepository.delete(person);
person = personRepository.findOne(personId);
assertNull(person);
}
}
如果您的Eclipse能正确地运行这些单元测试,那么恭喜,您已经成功地配置了Spring Data Neo4J。
定义数据实体
在确认了我们为使用Spring Data Neo4J所进行的项目配置不存在问题之后,我们就需要开始尝试定义操作Neo4J所需的实体了。如果需要将一个类型声明为Neo4J实体,那么我们就需要在相应的类型定义上使用@NodeEntity标记:
@NodeEntity
public class Person {
……
}
除此之外,我们还需要通过@GraphId标记标明用来记录ID的属性:
@NodeEntity
public class Person {
@GraphId
private Long id; public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
}
}
由于该域是如此常用,因此我们常常会将其移到基类实现中,并根据该域的值来重写hashCode()和equals()方法:
public abstract class AbstractEntity {
@GraphId
private Long id;
……
@Override
public boolean equals(Object obj) {
……
}
@Override
public int hashCode() {
……
}
}
此时,所有的Neo4J实体只需要从该类派生就能得到equals()和hashCode()的支持了。至于如何正确地实现equals()以及如何正确地实现hashCode(),网络上的讲解很多,这里就不再赘述。感兴趣的读者可以自行查看GitHub上的示例代码。
好,有了实体,下一步要做的就是定义实体之间的关系了。先让我们看一个如何创建简单关系的示例:
@NodeEntity
public class Person extends NamedEntity {
@Relationship(type="READER_OF")
private Set<Book> books;
……
} @NodeEntity
public class Book extends DescriptiveEntity {
@Relationship(type="READER_OF", direction=Relationship.INCOMING)
private Set<Person> readers;
……
}
上面的代码展示了如何在Person类和Book类之间创建简单的关系。可以看到,我们只需要创建对关系另一端实例的引用,并通过@Relationship标记在这些引用之上标明关系的名称即可。如果一个关系是有向的,例如READER_OF关系需要被解读为Person p is READER_OF Book b,那么我们就需要在关系的两端标明关系的方向。在上面的示例中,READER_OF关系的方向便是由Person指向Book。当然,我们也可以通过UNDIRECTED来标示一个关系是没有方向的。
当然,我们是为了方便才在Book中添加了指向Person实例的集合。如果在您的Book实体中添加这么个域并不会为您带来方便,那么您完全可以省略该域。而且该做法还会在一定程度上简化您编写代码的复杂度。让我们来看下面的一段用来在Person实例和Book实例之间建立关系的示例代码(详见测试代码BookRepositoryTest.testCRUDRelationships()):
@Test
public void testCRUDRelationships() {
……
// Test add readers
Book book2 = new Book();
book2.setName(TEST_BOOK_NAME_2);
book2 = bookRepository.save(book2); readers = new HashSet<Person>();
readers.add(person1);
person1.getBooks().add(book2);
book2.setReaders(readers);
book2 = bookRepository.save(book2);
……
}
您可能会问:为什么向Person实例添加一个对Book类实例的引用需要这么多行代码?答案就是,如果我们只更新了关系的一端却没有更新关系的另一端,那么关系两端所记录的关系就会出现不一致,进而导致Neo4J根本无法判断应该根据哪一端所记录的数据对数据库进行操作。您说是不?
往更深一步说,图形数据库中一个非常容易犯错的地方就是对图的修改会导致图处于一个非一致状态。在这种情况下,对这些数据的保存将可能导致图本身处于一个非期望的状态,并逐渐发展为混乱状态。例如在删除一个实例时没有维护图中其它结点对它的引用,那么该删除操作就可能会导致这些结点中所记录的引用是非法的,甚至使得整个数据库无法加载。您别不信,我们真遇到过。
所以说,图形数据库编程中,您一定要在每个对图的操作中保证图是处于一个合法的一致状态。这也便是为何我们常常在关系的两端都记录关系的原因:一旦其中一个结点有变,我们可以快速找到对它的引用,并对该引用进行维护。
您可能还有一个问题,那就是,图形数据库不是用来记录富关系的么?那我们应该如何在关系中记录额外的数据呢?此时我们就需要通过@RelationshipEntity标记来定义一个富关系,并进而在各个实体定义中使用该关系:
@RelationshipEntity(type="WRITER_OF")
public class WriterOf extends AbstractEntity {
@StartNode
private Person writer; @EndNode
private Book book; private Date startDate;
private Date endDate;
……
} @NodeEntity
public class Person extends NamedEntity {
@Relationship(type="WRITER_OF")
private Set<WriterOf> writings; @Relationship(type="READER_OF")
private Set<Book> books;
……
}
此时在我们的实体定义中所记录的不再是富关系另一端的实体集合,而是富关系本身。
相信经过这么一篇简短的介绍,您已经了解了如何使用Spring Data Neo4J来操作数据库了。如果您感兴趣,可以下载我放置在https://github.com/loveis715/Spring-Neo4J中的示例代码。
转载请注明原文地址并标明转载:http://www.cnblogs.com/loveis715/p/5425790.html
商业转载请事先与我联系:silverfox715@sina.com
公众号一定帮忙别标成原创,因为协调起来太麻烦了。。。
通过Spring Data Neo4J操作您的图形数据库的更多相关文章
- Spring DATA Neo4J(一)
Spring DATA Neo4J——简介 Spring Framework提供了一下模块来处理基于Java的应用程序的DAO层 Spring JDBC Spring ORM Spring DATA ...
- 使用Spring Data Redis操作Redis(集群版)
说明:请注意Spring Data Redis的版本以及Spring的版本!最新版本的Spring Data Redis已经去除Jedis的依赖包,需要自行引入,这个是个坑点.并且会与一些低版本的Sp ...
- spring data jpa 操作pipelinedb 的continuous view 与stream
一. 由于pipelinedb是postgreSQL的扩展,因此相关依赖于配置都合集成postgreSQL是一样的. springboot + spring data jpa + postgreSQL ...
- Spring Boot (五)Spring Data JPA 操作 MySQL 8
一.Spring Data JPA 介绍 JPA(Java Persistence API)Java持久化API,是 Java 持久化的标准规范,Hibernate是持久化规范的技术实现,而Sprin ...
- Spring Data Solr操作solr的简单案例
Spring Data Solr简介 虽然支持任何编程语言的能力具有很大的市场价值,你可能感兴趣的问题是:我如何将Solr的应用集成到Spring中?可以,Spring Data Solr就是为了方便 ...
- Spring Boot使用Spring Data Redis操作Redis(单机/集群)
说明:Spring Boot简化了Spring Data Redis的引入,只要引入spring-boot-starter-data-redis之后会自动下载相应的Spring Data Redis和 ...
- 使用Spring Data Redis操作Redis(单机版)
说明:请注意Spring Data Redis的版本以及Spring的版本!最新版本的Spring Data Redis已经去除Jedis的依赖包,需要自行引入,这个是个坑点.并且会与一些低版本的Sp ...
- spring data mongodb 操作
xml配置(mongo集群方式): <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=& ...
- spring data jap操作
package com.example.demo; import com.example.entity.UserJ; import com.example.respository.UserJRespo ...
随机推荐
- IT人常用的网站
一.网页设计类 蓝色理想 http://www.blueidea.com 网页设计师联盟 http://www.68design.net 网页设计大本营 http://www.code-123.com ...
- C# 开发系列(二)
1. 参考文档:http://www.yiibai.com/csharp/csharp_environment_setup.html 2. C# ,ASP.NET HTTP Authorization ...
- OC版二分查找
二分查找(也称折半查找)是很常见的一种在数组中查找数据的算法,作为一名程序员是应该必须会的.它的基础思想:获取数组的中间值,将数组分割成两份,利用中间值跟指定的值进行比较,如果中间值大于指定的值,就在 ...
- (简单) POJ 1062 昂贵的聘礼,Dijkstra。
Description 年轻的探险家来到了一个印第安部落里.在那里他和酋长的女儿相爱了,于是便向酋长去求亲.酋长要他用10000个金币作为聘礼才答应把女儿嫁给他.探险家 拿不出这么多金币,便请求酋长降 ...
- (中等) HDU 1043 Eight,经典搜索问题。
Problem Description The 15-puzzle has been around for over 100 years; even if you don't know it by t ...
- window环境变量
首先Window中有很多乱七八糟的路径变量之类的,归类下来有几类,主要是为了我们分清楚概念,以免搞的糊涂了. 1. Window系统的环境变量:顾名思义,就是系统级别的变量,或者利用我们编程的角度来讲 ...
- 10天学会phpWeChat——第八天:Form类,丰富表单提交的字段类型
通过前面七讲的系列教程,我们完成了一个包含后台并自适应PC+h5移动端的文章管理模块. 在实际的生产环境中,文章投稿.商品上传等操作并不会简单局限于一个text和textarea组成的表单.在实际中, ...
- iOS正则表达式 分类: ios技术 2015-07-14 14:00 35人阅读 评论(0) 收藏
一.什么是正则表达式 正则表达式,又称正规表示法,是对字符串操作的一种逻辑公式.正则表达式可以检测给定的字符串是否符合我们定义的逻辑,也可以从字符串中获取我们想要的特定部分.它可以迅速地用极简单的方式 ...
- 利用OpenSSL创建证书链并应用于IIS7
一.系统环境说明 Linux & OpenSSL Linux localhost -.el5 # SMP Tue Mar :: EDT x86_64 x86_64 x86_64 GNU/Lin ...
- Python中下划线---完全解读
Python 用下划线作为变量前缀和后缀指定特殊变量 _xxx 不能用'from module import *'导入 __xxx__ 系统定义名字 __xxx 类中的私有变量名 核心风格:避免用下划 ...