$ brew install neo4j
使用 Neo4j 存取資料
本指南將引導您使用 Spring Data Neo4j 建構應用程式的流程,該應用程式可在 Neo4j(一個圖形資料庫)中儲存和檢索資料。
您將建構什麼
您將使用 Neo4j 的 NoSQL 圖形資料儲存庫來建構一個嵌入式 Neo4j 伺服器、儲存實體和關係,並開發查詢。
您需要什麼
-
約 15 分鐘
-
您慣用的文字編輯器或 IDE
-
Java 17 或更高版本
-
您也可以直接將程式碼匯入到您的 IDE 中
如何完成本指南
如同大多數 Spring 入門指南,您可以從頭開始並完成每個步驟,或者您可以跳過您已熟悉的基本設定步驟。無論哪種方式,您最終都會得到可運作的程式碼。
若要從頭開始,請繼續前往 從 Spring Initializr 開始。
若要跳過基礎知識,請執行以下操作
-
下載 並解壓縮本指南的原始碼儲存庫,或使用 Git 克隆它:
git clone https://github.com/spring-guides/gs-accessing-data-neo4j.git
-
cd 進入
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。
-
按一下 Generate (產生)。
-
下載產生的 ZIP 檔案,這是一個已使用您的選擇設定的 Web 應用程式封存檔。
如果您的 IDE 具有 Spring Initializr 整合,您可以從您的 IDE 完成此程序。 |
您也可以從 GitHub 分叉專案,並在您的 IDE 或其他編輯器中開啟它。 |
啟動 Neo4j 伺服器
在您可以建構此應用程式之前,您需要設定 Neo4j 伺服器。
Neo4j 有一個您可以免費安裝的開放原始碼伺服器,或者您可以使用 Docker 執行它。
若要在已安裝 Homebrew 的 Mac 上安裝伺服器,請執行以下命令
如需其他選項,請造訪 https://neo4j.com/download/community-edition/。
安裝完成後,執行以下命令以使用其預設設定啟動它
$ neo4j start
您應該會看到類似以下的輸出
Starting Neo4j. Started neo4j (pid 96416). By default, it is available at https://127.0.0.1:7474/ There may be a short delay until the server is ready. See /usr/local/Cellar/neo4j/3.0.6/libexec/logs/neo4j.log for current status.
預設情況下,Neo4j 的使用者名稱和密碼為 neo4j
和 neo4j
。但是,它要求必須變更新帳戶密碼。若要執行此操作,請執行以下命令
curl -v -u neo4j:neo4j POST localhost:7474/user/neo4j/password -H "Content-type:application/json" -d "{\"password\":\"secret\"}"
這會將密碼從 neo4j
變更為 secret
— 請勿在生產環境中執行此操作!完成此步驟後,您應該可以執行本指南的其餘部分。
或者,若要使用 Neo4j Docker 映像執行。您可以使用 NEO4J_AUTH
環境變數變更密碼。
docker run \ --publish=7474:7474 --publish=7687:7687 \ --volume=$HOME/neo4j/data:/data \ --env NEO4J_AUTH=neo4j/password neo4j
定義簡單實體
Neo4j 捕捉實體及其關係,這兩個方面都同等重要。假設您正在建模一個系統,您在其中儲存每個人的記錄。但是,您也想要追蹤某人的同事(在本範例中為 teammates
)。透過 Spring Data Neo4j,您可以使用一些簡單的註釋來捕捉所有這些,如下列清單所示(在 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/modelling-data-neo4j
*/
@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 儲存它時,會建立一個新節點。此類別也有一個標記為 @GraphId
的 id
。Neo4j 在內部使用 @GraphId
來追蹤資料。
下一個重要的部分是 teammates
的集合。它是一個簡單的 Set<Person>
,但標記為 @Relationship
。這表示此集合的每個成員也預期以個別的 Person
節點存在。請注意方向如何設定為 UNDIRECTED
。這表示當您查詢 TEAMMATE
關係時,Spring Data Neo4j 會忽略關係的方向。
透過 worksWith()
方法,您可以輕鬆地將人員連結在一起。
最後,您有一個方便的 toString()
方法,可以列印出人員的姓名以及該人員的同事。
建立簡單查詢
Spring Data Neo4j 專注於在 Neo4j 中儲存資料。但它繼承了 Spring Data Commons 專案的功能,包括衍生查詢的能力。基本上,您不需要學習 Neo4j 的查詢語言。相反地,您可以編寫少量的方法,並讓系統為您編寫查詢。
若要查看其運作方式,請建立一個介面來查詢 Person
節點。下列清單(在 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 Community Edition 需要憑證才能存取。您可以透過設定一些屬性(在 src/main/resources/application.properties
中)來設定這些憑證,如下列清單所示
spring.neo4j.uri=bolt://127.0.0.1:7687 spring.neo4j.authentication.username=neo4j spring.neo4j.authentication.password=secret
這包括預設使用者名稱 (neo4j
) 和我們稍早選取的新設定密碼 (secret
)。
請勿將真實憑證儲存在您的原始碼儲存庫中。相反地,請使用 Spring Boot 的屬性覆寫在您的執行階段中設定它們。 |
完成此設定後,您可以將其連接起來並查看其外觀!
建立應用程式類別
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 Boot 的 SpringApplication.run()
來啟動應用程式,並叫用建構關係的 CommandLineRunner
。
在本例中,您建立了三個本機 Person
實例:Greg、Roy 和 Craig。最初,它們僅存在於記憶體中。請注意,目前沒有人是任何人的隊友。
首先,您找到 Greg,指示他與 Roy 和 Craig 共事,然後再次持久化他。請記住,隊友關係標記為 UNDIRECTED
(即雙向)。這表示 Roy 和 Craig 也已更新。
這就是為什麼當您需要更新 Roy 時。從 Neo4j 取得該記錄至關重要。在將 Craig 新增到清單之前,您需要 Roy 隊友的最新狀態。
為什麼沒有程式碼來取得 Craig 並新增任何關係?因為您已經擁有它了!Greg 早先將 Craig 標記為隊友,Roy 也是如此。這表示無需再次更新 Craig 的關係。當您反覆查看每個團隊成員並將其資訊列印到主控台時,您可以看到它。
最後,查看另一個查詢,您可以在其中向後查找,回答「誰與誰共事?」的問題。
下列清單顯示完成的 AccessingDataNeo4jApplication
類別(位於 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
執行應用程式。或者,您可以使用 ./gradlew build
建構 JAR 檔案,然後執行 JAR 檔案,如下所示
如果您使用 Maven,您可以使用 ./mvnw spring-boot:run
執行應用程式。或者,您可以使用 ./mvnw clean package
建構 JAR 檔案,然後執行 JAR 檔案,如下所示
此處描述的步驟會建立可執行 JAR。您也可以 建構傳統 WAR 檔案。 |
您應該會看到類似以下清單的內容(以及其他內容,例如查詢)
Before linking up with Neo4j... Greg's teammates => [] Roy's teammates => [] Craig's teammates => [] Lookup each person by name... Greg's teammates => [Roy, Craig] Roy's teammates => [Greg, Craig] Craig's teammates => [Roy, Greg]
您可以從輸出中看到,(最初)沒有人透過任何關係連結。然後,在您新增人員之後,他們會被連結在一起。最後,您可以看到方便的查詢,它會根據隊友來查找人員。
摘要
恭喜!您剛剛設定了一個嵌入式 Neo4j 伺服器、儲存了一些簡單的相關實體,並開發了一些快速查詢。
如果您想要輕鬆地使用基於超媒體的 RESTful 前端公開 Neo4j 儲存庫,請閱讀 使用 REST 存取 Neo4j 資料。 |