在前面的一篇文章《图形数据库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
公众号必定帮忙别标成原创,由于协调起来太麻烦了。。。