共计 8507 个字符,预计需要花费 22 分钟才能阅读完成。
原题目:Spring 认证中国教育管理中心 - 理解如何在 Neo4j 的 NoSQL 数据存储中长久化对象和关系。(Spring 中国教育管理中心)
Spring 认证指南:如何在 Neo4j 的 NoSQL 数据存储中长久化对象和关系
本指南将疏导您实现应用 Spring Data Neo4j 构建应用程序的过程,该应用程序在 Neo4j 中存储数据并从中检索数据,Neo4j 是一个基于图形的数据库。
你将建造什么
您将应用 Neo4j 的 NoSQL 基于图形的数据存储来构建嵌入式 Neo4j 服务器、存储实体和关系以及开发查问。
你须要什么
约 15 分钟
最喜爱的文本编辑器或 IDE
JDK 1.8 或更高版本
Gradle 4+ 或 Maven 3.2+
您还能够将代码间接导入 IDE:弹簧工具套件 (STS)IntelliJ IDEA
如何实现本指南
像大多数 Spring 入门指南一样,您能够从头开始并实现每个步骤,也能够绕过您曾经相熟的根本设置步骤。无论哪种形式,您最终都会失去工作代码。
要从头开始,请持续从 Spring Initializr 开始。
要跳过基础知识,请执行以下操作:
下载并解压本指南的源代码库,或应用 Git 克隆它:git clone https://github.com/spring-gui…
光盘进入 gs-accessing-data-neo4j/initial
跳转到定义一个简略实体。
实现后,您能够对照中的代码查看后果
gs-accessing-data-neo4j/complete。
从 Spring Initializr 开始
您能够应用这个事后初始化的我的项目并单击 Generate 下载 ZIP 文件。此我的项目配置为适宜本教程中的示例。
手动初始化我的项目:
导航到 https://start.spring.io。该服务提取应用程序所需的所有依赖项,并为您实现大部分设置。
抉择 Gradle 或 Maven 以及您要应用的语言。本指南假设您抉择了 Java。
单击 Dependencies 并抉择 Spring Data Neo4j。
单击生成。
下载生成的 ZIP 文件,该文件是依据您的抉择配置的 Web 应用程序的存档。
如果您的 IDE 具备 Spring Initializr 集成,您能够从您的 IDE 实现此过程。
你也能够从 Github 上 fork 我的项目并在你的 IDE 或其余编辑器中关上它。
建设 Neo4j 服务器
在构建此应用程序之前,您须要设置 Neo4j 服务器。
Neo4j 有一个开源服务器,您能够收费装置。
在装置了 Homebrew 的 Mac 上,运行以下命令:
$ 酿造装置 neo4j
无关其余选项,请拜访
https://neo4j.com/download/co…。
装置后,通过运行以下命令以默认设置启动它:
$ neo4j 开始
您应该会看到相似于以下内容的输入:
启动 Neo4j。
启动 neo4j (pid 96416)。默认状况下,它位于 http://localhost:7474/
在服务器筹备好之前可能会有短暂的提早。
无关以后状态,请参见 /usr/local/Cellar/neo4j/3.0.6/libexec/logs/neo4j.log。
默认状况下,Neo4j 的用户名和明码为 neo4jand neo4j。然而,它须要更改新的帐户明码。为此,请运行以下命令:
curl -v -u neo4j:neo4j POST localhost:7474/user/neo4j/password -H “Content-type:application/json” -d “{\”password\”:\”secret\”}”
这会将明码从 更改 neo4j 为 secret - 在生产中不要做的事件!实现该步骤后,您应该筹备好运行本指南的其余部分。
定义一个简略的实体
Neo4j 捕捉实体及其关系,这两个方面等同重要。设想一下,您正在为一个零碎建模,您在其中存储每个人的记录。然而,您还想跟踪一个人的共事(teammates 在本例中)。应用 Spring Data Neo4j,您能够应用一些简略的正文来捕捉所有这些,如以下清单(in 中
src/main/java/com/example/accessingdataneo4j/Person.java)所示:
package com.example.accessingdataneo4j;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Property;
import org.springframework.data.neo4j.core.schema.Relationship;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
@Node
public class Person {
@Id @GeneratedValue private Long id;
private String name;
private Person() {
// Empty constructor required as of Neo4j API 2.0.5
};
public Person(String name) {
this.name = name;
}
/**
- Neo4j doesn’t REALLY have bi-directional relationships. It just means when querying
- to ignore the direction of the relationship.
- https://dzone.com/articles/mo…
*/
@Relationship(type = “TEAMMATE”)
public Set<Person> teammates;
public void worksWith(Person person) {
if (teammates == null) {teammates = new HashSet<>();
}
teammates.add(person);
}
public String toString() {
return this.name + "'s teammates =>"
+ Optional.ofNullable(this.teammates).orElse(Collections.emptySet()).stream()
.map(Person::getName)
.collect(Collectors.toList());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在这里,您有一个 Person 只有一个属性的类:name.
该类 Person 用 正文 @NodeEntity。Neo4j 存储它时,会创立一个新节点。这个类也有一个 id 标记 @GraphId。Neo4j@GraphId 在外部应用来跟踪数据。
下一个重要的局部是 teammates. 它很简略 Set<Person>,但被标记为 @Relationship。这意味着这个汇合的每个成员都应该作为一个独自的 Person 节点存在。留神方向是如何设置的 UNDIRECTED。这意味着当您查问 TEAMMATE 关系时,Spring Data Neo4j 会疏忽关系的方向。
应用该 worksWith()办法,您能够轻松地将人们分割在一起。
最初,您有一个不便的 toString()办法能够打印出该人的姓名和该人的共事。
创立简略查问
Spring Data Neo4j 专一于在 Neo4j 中存储数据。但它继承了 Spring Data Commons 我的项目的性能,包含派生查问的能力。实质上,您不须要学习 Neo4j 的查询语言。相同,您能够编写一些办法并让查问为您编写。
要理解其工作原理,请创立一个查问 Person 节点的接口。以下清单 (in
src/main/java/com/example/accessingdataneo4j/PersonRepository.java) 显示了这样一个查问:
package com.example.accessingdataneo4j;
import java.util.List;
import org.springframework.data.neo4j.repository.Neo4jRepository;
public interface PersonRepository extends Neo4jRepository<Person, Long> {
Person findByName(String name);
List<Person> findByTeammatesName(String name);
}
PersonRepository 扩大 Neo4jRepository 接口并插入其操作的类型:Person. 该接口带有许多操作,包含规范的 CRUD(创立、读取、更新和删除)操作。
然而您能够通过申明它们的办法签名来定义其余查问。在这种状况下,您增加了 findByName,它会查找类型节点 Person 并找到与 上匹配的节点 name。您还有 findByTeammatesName,它会寻找一个 Person 节点,深刻到 teammates 字段的每个条目,并依据队友的 name.
拜访 Neo4j 的权限
Neo4j 社区版须要凭据能力拜访它。您能够通过设置几个属性(在 中
src/main/resources/application.properties)来配置这些凭据,如以下清单所示:
spring.neo4j.uri=bolt://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
这包含默认用户名 (neo4j) 和咱们之前抉择的新设置的明码 (secret)。
不要将实在凭据存储在您的源存储库中。相同,应用 Spring Boot 的 property overrides 在运行时配置它们。
创立应用程序类
Spring Initializr 为应用程序创立一个简略的类。以下清单显示了 Initializr 为本示例创立的类(在 中
src/main/java/com/example/accessingdataneo4j/AccessingDataNeo4jApplication.java):
package com.example.accessingdataneo4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AccessingDataNeo4jApplication {
public static void main(String[] args) {
SpringApplication.run(AccessingDataNeo4jApplication.class, args);
}
}
@SpringBootApplication 是一个不便的正文,它增加了以下所有内容:
@Configuration: 将类标记为应用程序上下文的 bean 定义源。
@EnableAutoConfiguration:通知 Spring Boot 依据类门路设置、其余 bean 和各种属性设置开始增加 bean。例如,如果 spring-webmvc 位于类门路上,则此正文将应用程序标记为 Web 应用程序并激活要害行为,例如设置 DispatcherServlet.
@ComponentScan: 通知 Spring 在包中查找其余组件、配置和服务 com/example,让它找到控制器。
该 main()办法应用 Spring Boot 的 SpringApplication.run()办法来启动应用程序。您是否留神到没有一行 XML?也没有 web.xml 文件。这个 Web 应用程序是 100% 纯 Java,您不用解决任何管道或基础设施的配置。
只有它们蕴含在 @SpringBootApplication 类的同一个包(或子包)中,Spring Boot 就会主动解决这些存储库。为了更好地管制注册过程,您能够应用 @EnableNeo4jRepositories 正文。
默认状况下,@EnableNeo4jRepositories 扫描以后包以查找扩大 Spring Data 存储库接口之一的任何接口。basePackageClasses=MyRepository.class 如果您的我的项目布局有多个我的项目并且找不到您的存储库,您能够应用它来平安地通知 Spring Data Neo4j 按类型扫描不同的根包。
显示记录输入。该服务应在几秒钟内启动并运行。
PersonRepository 当初主动拆卸您之前定义的实例。Spring Data Neo4j 动静实现该接口并插入所需的查问代码以满足接口的任务。
该 main 办法应用 Spring BootSpringApplication.run()启动应用程序并调用 CommandLineRunner 构建关系的办法。
在本例中,您将创立三个本地 Person 实例:Greg、Roy 和 Craig。最后,它们只存在于内存中。请留神,没有人是任何人的队友(目前)。
起初,你找到 Greg,表明他与 Roy 和 Craig 单干,而后再次保持他。请记住,队友关系被标记为 UNDIRECTED(即双向)。这意味着 Roy 和 Craig 也已更新。
这就是为什么当您须要更新 Roy 时。首先从 Neo4j 获取该记录至关重要。在将 Craig 增加到列表之前,您须要理解 Roy 队友的最新状态。
为什么没有代码能够获取 Craig 并增加任何关系?因为你曾经领有了!格雷格早些时候将克雷格标记为队友,罗伊也是如此。这意味着无需再次更新 Craig 的关系。当您遍历每个团队成员并将他们的信息打印到控制台时,您能够看到它。
最初,查看您向后看的其余查问,答复“谁与谁一起工作?”的问题。
以下清单显示了实现的
AccessingDataNeo4jApplication 类 (at
src/main/java/com/example/accessingdataneo4j/AccessingDataNeo4jApplication.java):
package com.example.accessingdataneo4j;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
@SpringBootApplication
@EnableNeo4jRepositories
public class AccessingDataNeo4jApplication {
private final static Logger log = LoggerFactory.getLogger(AccessingDataNeo4jApplication.class);
public static void main(String[] args) throws Exception {SpringApplication.run(AccessingDataNeo4jApplication.class, args);
System.exit(0);
}
@Bean
CommandLineRunner demo(PersonRepository personRepository) {
return args -> {personRepository.deleteAll();
Person greg = new Person("Greg");
Person roy = new Person("Roy");
Person craig = new Person("Craig");
List<Person> team = Arrays.asList(greg, roy, craig);
log.info("Before linking up with Neo4j...");
team.stream().forEach(person -> log.info("\t" + person.toString()));
personRepository.save(greg);
personRepository.save(roy);
personRepository.save(craig);
greg = personRepository.findByName(greg.getName());
greg.worksWith(roy);
greg.worksWith(craig);
personRepository.save(greg);
roy = personRepository.findByName(roy.getName());
roy.worksWith(craig);
// We already know that roy works with greg
personRepository.save(roy);
// We already know craig works with roy and greg
log.info("Lookup each person by name...");
team.stream().forEach(person -> log.info("\t" + personRepository.findByName(person.getName()).toString()));
List<Person> teammates = personRepository.findByTeammatesName(greg.getName());
log.info("The following have Greg as a teammate...");
teammates.stream().forEach(person -> log.info("\t" + person.getName()));
};
}
}
构建一个可执行的 JAR
您能够应用 Gradle 或 Maven 从命令行运行应用程序。您还能够构建一个蕴含所有必要依赖项、类和资源的单个可执行 JAR 文件并运行它。构建可执行 jar 能够在整个开发生命周期、跨不同环境等中轻松地将服务作为应用程序交付、版本化和部署。
如果您应用 Gradle,则能够应用./gradlew bootRun. 或者,您能够应用构建 JAR 文件./gradlew build,而后运行 JAR 文件,如下所示:
java -jar build/libs/gs-accessing-data-neo4j-0.1.0.jar
如果您应用 Maven,则能够应用./mvnw spring-boot:run. 或者,您能够应用构建 JAR 文件,./mvnw clean package 而后运行该 JAR 文件,如下所示:
java -jar 指标 /gs-accessing-data-neo4j-0.1.0.jar
此处形容的步骤创立了一个可运行的 JAR。您还能够构建经典的 WAR 文件。
您应该会看到相似于以下列表的内容(还有其余内容,例如查问):
在与 Neo4j 连贯之前 …
格雷格的队友 => []
罗伊的队友 => []
克雷格的队友 => []
按姓名查找每个人 …
格雷格的队友 => [罗伊,克雷格]
罗伊的队友 => [格雷格,克雷格]
克雷格的队友 => [罗伊,格雷格]
您能够从输入中看到(最后)没有人通过任何关系连贯。而后,在您增加人员后,他们被捆绑在一起。最初,您能够看到依据队友查找人员的便捷查问。
总结
祝贺!您刚刚设置了一个嵌入式 Neo4j 服务器,存储了一些简略的相干实体,并开发了一些疾速查问。