開始使用
我們為 SDN 提供 Spring Boot 起始程式。請透過您的相依性管理包含起始程式模組,並設定要使用的 bolt URL,例如 spring.neo4j.uri=bolt://localhost:7687
。此起始程式假設伺服器已停用身分驗證。由於 SDN 起始程式相依於 Java Driver 的起始程式,因此所有關於組態的說明也適用於此處。如需可用屬性的參考,請在 spring.neo4j
命名空間中使用 IDE 的自動完成功能。
SDN 支援
-
廣為人知且易於理解的命令式程式設計模型 (非常類似 Spring Data JDBC 或 JPA)
-
基於 Reactive Streams 的反應式程式設計,包括完全支援 反應式交易。
這些都包含在同一個二進位檔案中。反應式程式設計模型在資料庫端需要 4+ Neo4j 伺服器,而在另一端需要反應式 Spring。
準備資料庫
在此範例中,我們將停留在 電影圖 中,因為每個 Neo4j 實例都免費提供。
如果您沒有正在執行的資料庫但已安裝 Docker,請執行
docker run --publish=7474:7474 --publish=7687:7687 -e 'NEO4J_AUTH=neo4j/secret' neo4j:5
您現在可以存取 http://localhost:7474。上述命令將伺服器的密碼設定為 secret
。請注意提示符號中準備執行的命令 (:play movies
)。執行它以使用一些測試資料填入您的資料庫。
建立新的 Spring Boot 專案
設定 Spring Boot 專案最簡單的方式是 start.spring.io (它也整合在主要的 IDE 中,如果您不想使用網站的話)。
選取 "Spring Web Starter" 以取得建立基於 Spring 的網路應用程式所需的所有相依性。Spring Initializr 將負責為您建立有效的專案結構,並為選定的建置工具準備好所有檔案和設定。
使用 Maven
您可以對 Spring Initializer 發出 curl 請求,以建立基本的 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
。由於此起始程式尚未在 initializer 上,因此您必須將以下相依性手動新增至您的 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
如果您是現有的專案,您也可以手動新增相依性。
使用 Gradle
概念相同,只需產生一個 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
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-neo4j'
}
如果您是現有的專案,您也可以手動新增相依性。
設定專案
現在在您最喜歡的 IDE 中開啟這些專案中的任何一個。找到 application.properties
並設定您的 Neo4j 憑證
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=verysecret
這是連線到 Neo4j 實例所需的最低限度設定。
當您使用此起始程式時,無需新增驅動程式的任何程式化組態。SDN 儲存庫將由此起始程式自動啟用。 |
設定 Neo4j Cypher-DSL
根據您應用程式執行的 Neo4j 版本,建議您設定 Neo4j Cypher-DSL 執行的方言。使用的預設方言是以 Neo4j 4.4 為目標,作為 Neo4j 的 LTS 版本。這可以透過定義 Cypher-DSL Configuration
bean 來變更。
@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
如下
module-info.java
專案,旨在在模組路徑上使用 Spring Data Neo4jmodule 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 也包含儲存庫:這些儲存庫必須匯出,才能由 spring.beans 、spring.context 和 spring.data.commons 存取。如果您不想將它們匯出到全世界,您可以將它們限制為這些模組。 |
建立您的網域
我們的網域層應完成兩件事
-
將您的圖對應到物件
-
提供對這些物件的存取
範例節點實體
SDN 完全支援不可修改的實體,適用於 Java 和 Kotlin 中的 data
類別。因此,我們將在此處著重於不可變的實體,MovieEntity.java 顯示了這樣一個實體。
SDN 支援 Neo4j Java Driver 支援的所有資料類型,請參閱「Cypher 類型系統」章節內的 將 Neo4j 類型對應到原生語言類型。未來版本將支援其他轉換器。 |
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。此處顯示的電影類別使用屬性 title 作為唯一的業務金鑰。如果您沒有這樣的唯一金鑰,您可以使用 @Id 和 @GeneratedValue 的組合來設定 SDN 以使用 Neo4j 的內部 ID。我們也為 UUID 提供產生器。 |
3 | 這顯示了 @Property 作為一種為欄位使用與圖屬性不同名稱的方式。 |
4 | 這定義了與類型為 PersonEntity 的類別和關係類型 ACTED_IN 的關係 |
5 | 這是您的應用程式碼要使用的建構子。 |
作為一般性評論:使用內部產生的 ID 的不可變實體有點矛盾,因為 SDN 需要一種方法來使用資料庫產生的值來設定欄位。
如果您找不到好的業務金鑰,或者不想使用 ID 產生器,則此處是使用內部產生的 ID 以及常規建構子和 SDN 使用的所謂 wither 方法的相同實體
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。它建立一個新的實體並相應地設定欄位,而不會修改原始實體,從而使其成為不可變的。 |
您當然可以將 SDN 與 Kotlin 一起使用,並使用 Kotlin 的資料類別來建模您的網域。如果您想要或需要完全停留在 Java 內,Project Lombok 是一種替代方案。
宣告 Spring Data 儲存庫
您基本上有兩個選項:您可以使用與儲存區無關的方式使用 SDN,並使您的網域特定擴充以下其中之一
-
org.springframework.data.repository.Repository
-
org.springframework.data.repository.CrudRepository
-
org.springframework.data.repository.reactive.ReactiveCrudRepository
-
org.springframework.data.repository.reactive.ReactiveSortingRepository
相應地選擇命令式和反應式。
雖然技術上並未禁止,但不建議在同一個應用程式中混合使用命令式和反應式資料庫存取。我們不會為您提供像這樣的場景支援。 |
另一個選項是確定儲存區特定的實作,並獲得我們開箱即用的所有方法。這種方法的優點也是其最大的缺點:一旦公開,所有這些方法都將成為您 API 的一部分。大多數時候,拿走一些東西比事後添加東西更難。此外,使用儲存區特定性會將您的儲存區洩漏到您的網域中。從效能的角度來看,沒有任何損失。
適用於上述任何電影實體的反應式儲存庫看起來像這樣
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 的相應文件或查看我們的範例程式碼。 |