入門

我們為 SDN 提供了一個 Spring Boot starter。請透過您的依賴管理引入 starter 模組,並配置要使用的 bolt URL,例如 spring.neo4j.uri=bolt://:7687。該 starter 假定伺服器已停用身份驗證。由於 SDN starter 依賴於 Java Driver 的 starter,因此那裡提到的所有配置事項也適用於此處。有關可用屬性的參考,請使用您 IDE 在 spring.neo4j 名稱空間下的自動完成功能。

SDN 支援

  • 眾所周知且易於理解的指令式程式設計模型(與 Spring Data JDBC 或 JPA 非常相似)

  • 基於 Reactive Streams 的響應式程式設計,包括對響應式事務的完全支援。

所有這些都包含在同一個二進位制檔案中。響應式程式設計模型需要資料庫端使用 4+ 版本的 Neo4j 伺服器,另一端使用響應式 Spring。

準備資料庫

對於此示例,我們使用 電影圖,因為每個 Neo4j 例項都免費附帶此圖。

如果您沒有執行中的資料庫,但安裝了 Docker,請執行

在 Docker 中啟動本地 Neo4j 例項。
docker run --publish=7474:7474 --publish=7687:7687 -e 'NEO4J_AUTH=neo4j/secret' neo4j:5

您現在可以訪問 https://:7474。上述命令將伺服器密碼設定為 secret。請注意提示符中已準備好執行的命令 (:play movies)。執行該命令以用一些測試資料填充您的資料庫。

建立一個新的 Spring Boot 專案

設定 Spring Boot 專案最簡單的方法是使用 start.spring.io(此網站也整合在主要的 IDE 中,如果您不想使用網站的話)。

選擇 "Spring Web Starter" 以獲取建立基於 Spring 的 Web 應用程式所需的所有依賴。Spring Initializr 將為您建立一個有效的專案結構,其中包含所選構建工具的所有檔案和設定。

使用 Maven

您可以對 Spring Initializer 發起 curl 請求來建立一個基本的 Maven 專案

使用 Spring Initializr 建立一個基本的 Maven 專案
curl https://start.spring.io/starter.tgz \
  -d dependencies=webflux,data-neo4j  \
  -d bootVersion=3.2.0 \
  -d baseDir=Neo4jSpringBootExample \
  -d name=Neo4j%20SpringBoot%20Example | tar -xzvf -

這將建立一個新資料夾 Neo4jSpringBootExample。由於此 starter 尚未新增到 initializer 中,您必須手動將以下依賴新增到您的 pom.xml

在 Maven 專案中包含 spring-data-neo4j-spring-boot-starter
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>

如果專案已存在,您也可以手動新增此依賴。

使用 Gradle

思路相同,只需生成一個 Gradle 專案即可

使用 Spring Initializr 建立一個基本的 Gradle 專案
curl https://start.spring.io/starter.tgz \
  -d dependencies=webflux,data-neo4j \
  -d type=gradle-project \
  -d bootVersion=3.2.0 \
  -d baseDir=Neo4jSpringBootExampleGradle \
  -d name=Neo4j%20SpringBoot%20Example | tar -xzvf -

Gradle 的依賴如下所示,必須新增到 build.gradle

在 Gradle 專案中包含 spring-data-neo4j-spring-boot-starter
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
}

如果專案已存在,您也可以手動新增此依賴。

配置專案

現在在您喜歡的 IDE 中開啟這些專案。找到 application.properties 並配置您的 Neo4j 憑據

spring.neo4j.uri=bolt://:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=verysecret

這是連線到 Neo4j 例項所需的最低配置。

使用此 starter 時,無需新增任何驅動程式的程式化配置。SDN repository 將透過此 starter 自動啟用。

配置 Neo4j Cypher-DSL

根據您執行應用程式所使用的 Neo4j 版本,建議配置 Neo4j Cypher-DSL 執行的方言。預設使用的方言是針對 Neo4j 的 LTS 版本 4.4。可以透過定義一個 Cypher-DSL Configuration bean 來更改此設定。

使 Cypher-DSL 使用 Neo4j 5 方言
@Bean
Configuration cypherDslConfiguration() {
	return Configuration.newConfig()
                .withDialect(Dialect.NEO4J_5).build();
}
儘管 Spring Data Neo4j 會盡力相容 Neo4j 5 和預設方言的組合,但始終建議明確定義方言。例如,這將導致更最佳化的查詢,併為較新的 Neo4j 版本利用 elementId()

在模組路徑上執行

Spring Data Neo4j 可以在模組路徑上執行。它的自動模組名稱是 spring.data.neo4j。由於當前 Spring Data 構建設定的限制,它本身不提供模組。因此,它使用一個自動但穩定的模組名稱。然而,它確實依賴於一個模組化的庫(Cypher-DSL)。由於上述限制,我們無法在您的專案上表達對此庫的需求,因為缺少 module-info.java

因此,您的專案要在模組路徑上執行 Spring Data Neo4j 6.1+ 所需的最少 module-info.java 如下所示

一個旨在在模組路徑上使用 Spring Data Neo4j 的專案中的 module-info.java
module your.module {

	requires org.neo4j.cypherdsl.core;

	requires spring.data.commons;
	requires spring.data.neo4j;

	opens your.domain to spring.core; (1)

	exports your.domain; (2)
}
1 Spring Data Neo4j 使用 Spring Data Commons 及其反射能力,因此您至少需要將您的域包開放給 spring.core
2 我們在此假設 your.domain 也包含 repositories:它們必須匯出才能被 spring.beansspring.contextspring.data.commons 訪問。如果您不想將它們匯出到所有模組,可以將它們限制為這些模組。

建立您的域

我們的域層應完成兩件事

  • 將您的圖對映到物件

  • 提供對這些物件的訪問

節點實體示例

SDN 完全支援不可修改的實體,適用於 Java 和 Kotlin 中的 data 類。因此,我們將重點關注這裡的不可變實體,MovieEntity.java 展示了這樣的實體。

SDN 支援 Neo4j Java Driver 支援的所有資料型別,請參閱章節“Cypher 型別系統”中的 將 Neo4j 型別對映到本機語言型別。未來的版本將支援額外的轉換器。
MovieEntity.java
import java.util.ArrayList;
import java.util.List;

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.Relationship.Direction;

@Node("Movie") (1)
public class MovieEntity {

	@Id (2)
	private final String title;

	@Property("tagline") (3)
	private final String description;

	@Relationship(type = "ACTED_IN", direction = Direction.INCOMING) (4)
	private List<Roles> actorsAndRoles = new ArrayList<>();

	@Relationship(type = "DIRECTED", direction = Direction.INCOMING)
	private List<PersonEntity> directors = new ArrayList<>();

	public MovieEntity(String title, String description) { (5)
		this.title = title;
		this.description = description;
	}

	// Getters omitted for brevity
}
1 @Node 用於將此類標記為託管實體。它還用於配置 Neo4j 標籤。如果只使用簡單的 @Node,標籤預設為類名。
2 每個實體都必須有一個 ID。此處顯示的 Movie 類使用屬性 title 作為唯一的業務鍵。如果您沒有這樣的唯一鍵,可以使用 @Id@GeneratedValue 的組合來配置 SDN 使用 Neo4j 的內部 ID。我們還提供了 UUID 的生成器。
3 這展示了 @Property 作為一種方式,使得欄位名稱可以與圖屬性的名稱不同。
4 這定義了與 PersonEntity 型別的類的關係以及關係型別 ACTED_IN
5 這是供您的應用程式程式碼使用的建構函式。

普遍的說法:使用內部生成 ID 的不可變實體有點矛盾,因為 SDN 需要一種方法來使用資料庫生成的值設定欄位。

如果您找不到好的業務鍵或不想使用 ID 生成器,下面是使用內部生成 ID 的相同實體,結合常規建構函式和所謂的 wither 方法,SDN 使用此方法

MovieEntity.java
import org.springframework.data.neo4j.core.schema.GeneratedValue;
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.annotation.PersistenceConstructor;

@Node("Movie")
public class MovieEntity {

	@Id @GeneratedValue
	private Long id;

	private final String title;

	@Property("tagline")
	private final String description;

	public MovieEntity(String title, String description) { (1)
		this.id = null;
		this.title = title;
		this.description = description;
	}

	public MovieEntity withId(Long id) { (2)
		if (this.id.equals(id)) {
			return this;
		} else {
			MovieEntity newObject = new MovieEntity(this.title, this.description);
			newObject.id = id;
			return newObject;
		}
	}
}
1 這是供您的應用程式程式碼使用的建構函式。它將 ID 設定為 null,因為包含內部 ID 的欄位不應該被修改。
2 這是 id 屬性的所謂 wither 方法。它建立一個新實體並相應地設定欄位,而不修改原始實體,從而使其不可變。

當然,您可以使用 Kotlin 的資料類與 SDN 一起建模您的域。如果您想或需要完全使用 Java,Project Lombok 是另一種選擇。

宣告 Spring Data repository

您基本上有兩種選擇:您可以以儲存無關的方式使用 SDN 並使您的領域特定 repository 擴充套件以下介面之一

  • org.springframework.data.repository.Repository

  • org.springframework.data.repository.CrudRepository

  • org.springframework.data.repository.reactive.ReactiveCrudRepository

  • org.springframework.data.repository.reactive.ReactiveSortingRepository

相應地選擇命令式或響應式。

雖然技術上不禁止,但不建議在同一個應用程式中混合使用命令式和響應式資料庫訪問。我們不會為您提供此類場景的支援。

另一種選擇是選擇特定儲存的實現並獲得我們開箱即用的所有方法。這種方法的優點也是其最大的缺點:一旦公開,所有這些方法都將成為您 API 的一部分。大多數時候,移除某些內容比之後新增東西更困難。此外,使用特定於儲存的方法會將您的儲存洩露到您的域中。從效能角度來看,沒有懲罰。

一個適用於上述任何電影實體的響應式 repository 如下所示

MovieRepository.java
import reactor.core.publisher.Mono;

import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;

public interface MovieRepository extends ReactiveNeo4jRepository<MovieEntity, String> {

	Mono<MovieEntity> findOneByTitle(String title);
}
響應式程式碼的測試使用 reactor.test.StepVerifier 完成。請參閱 Project Reactor 的相應文件或檢視我們的示例程式碼。