Neo4j - 圖資料庫基礎

ityml發表於2024-04-08

一、Neo4J相關介紹

1.為什麼需要圖資料庫

  隨著社交、電商、金融、零售、物聯網等行業的快速發展,現實社會織起了了一張龐大而複雜的關係
網,傳統資料庫很難處理關係運算。大資料行業需要處理的資料之間的關係隨資料量呈幾何級數增長,
急需一種支援海量複雜資料關係運算的資料庫,圖資料庫應運而生。
世界上很多著名的公司都在使用圖資料庫,比如:

  • 社交領域:Facebook, Twitter,Linkedin用它來管理社交關係,實現好友推薦
  • 零售領域:eBay,沃爾瑪使用它實現商品實時推薦,給買家更好的購物體驗
  • 金融領域:摩根大通,花旗和瑞銀等銀行在用圖資料庫做風控處理
  • 汽車製造領域:沃爾沃,戴姆勒和豐田等頂級汽車製造商依靠圖資料庫推動創新制造解決方案
  • 電信領域:Verizon, Orange和AT&T 等電信公司依靠圖資料庫來管理網路,控制訪問並支援客戶
    360
  • 酒店領域:萬豪和雅高酒店等頂級酒店公司依使用圖資料庫來管理複雜且快速變化的庫存
    圖資料庫並非指儲存圖片的資料庫,而是以圖資料結構儲存和查詢資料。

  圖資料庫是基於圖論實現的一種NoSQL資料庫,其資料儲存結構和資料查詢方式都是以圖論為基礎的,
圖資料庫主要用於儲存更多的連線資料.

  圖論〔Graph Theory〕是數學的一個分支。它以圖為研究物件圖論中的圖是由若干給定的點及連
接兩點的線所構成的圖形,這種圖形通常用來描述某些事物之間的某種特定關係,用點代表事物,
用連線兩點的線表示相應兩個事物間具有這種關係。

image.png

方案1:Google+

  使用 Google+(GooglePlus)應用程式來了解現實世界中 Graph 資料庫的需求。 觀察下面的圖表。

在這裡,我們用圓圈表示了 Google+應用個人資料。

image.png

在上圖中,輪廓“A”具有圓圈以連線到其他輪廓:家庭圈(B,C,D)和朋友圈(B,C)。

再次,如果我們開啟配置檔案“B”,我們可以觀察以下連線的資料。

image.png

  像這樣,這些應用程式包含大量的結構化,半結構化和非結構化的連線資料。 在 RDBMS 資料庫中表示這種非結構化連線資料並不容易。

  如果我們在 RDBMS 資料庫中儲存這種更多連線的資料,那麼檢索或遍歷是非常困難和緩慢的。

  所以要表示或儲存這種更連線的資料,我們應該選擇一個流行的圖資料庫。

  圖形DBMS非常容易地儲存這種更多連線的資料。 它將每個配置檔案資料作為節點儲存在內部,它與相鄰節點連線的節點,它們透過關係相互連線。

  他們儲存這種連線的資料與上面的圖表中的相同,這樣檢索或遍歷是非常容易和更快的。

方案2:Facebook

  利用 Facebook 應用程式瞭解現實世界中 Graph 資料庫的需求。

image.png

  在上面的圖中,Facebook Profile“A”已經連線到他的朋友,喜歡他的一些朋友,傳送訊息給他的一些朋友,跟隨他喜歡的一些名人。

  這意味著大量的連線資料配置檔案A.如果我們開啟其他配置檔案,如配置檔案B,我們將看到類似的大量的連線資料。

注- 透過觀察上述兩個應用程式,它們有很多更多的連線資料。 它是非常容易儲存和檢索,這種更連線的資料與圖形資料庫。

2.特定和優勢

  關係查詢效能對比 在資料關係中心,圖形資料庫在查詢速度方面非常高效,即使對於深度和複雜的查詢
也是如此。在關係型資料庫和圖資料庫(Neo4j)之間進行了實驗:在一個社交網路裡找到最大深度為5的
朋友的朋友,他們的資料集包括100萬人,每人約有50個朋友。
實驗結果如下:

image.png

對比關係型資料庫

image.png

各種NOSQL對比

分類 資料模型 優勢 劣勢 舉例
鍵值對資料庫 雜湊表 查詢速度快 資料無結構化,通常只被當作字串或者二進位制資料 Redis
列儲存資料庫 列式資料儲存 查詢速度快;支援分佈橫向擴充套件;資料壓縮率高 功能相對受限 HBase
文件型資料庫 鍵值對擴充套件 資料結構要求不嚴格;表結構可變;不需要預先定義表結構 查詢效能不高,缺乏統一的查詢語法 MongoDB
圖資料庫 節點和關係組成的圖 利用圖結構相關演算法(最短路徑、節點度關係查詢等) 可能需要對整個圖做計算,不利於圖資料分佈儲存 Neo4j

3.什麼是Neo4j

  Neo4j是一個開源的NoSQL圖形資料庫,2003 年開始開發,使用 scala和java 語言,2007年開始釋出。

  • 是世界上最先進的圖資料庫之一,提供原生的圖資料儲存,檢索和處理;
  • 採用屬性圖模型(Property graph model),極大的完善和豐富圖資料模型;
  • 專屬查詢語言 Cypher,直觀,高效;

官網: https://neo4j.com/
Neo4j的特性:

  • SQL就像簡單的查詢語言Neo4j CQL
  • 它遵循屬性圖資料模型
  • 它透過使用Apache Lucence支援索引
  • 它支援UNIQUE約束
  • 它包含一個用於執行CQL命令的UI:Neo4j資料瀏覽器
  • 它支援完整的ACID(原子性,一致性,隔離性和永續性)規則
  • 它採用原生圖形庫與本地GPE(圖形處理引擎)
  • 它支援查詢的資料匯出到JSON和XLS格式
  • 它提供了REST API,可以被任何程式語言(如Java,Spring,Scala等)訪問
  • 它提供了可以透過任何UI MVC框架(如Node JS)訪問的Java指令碼
  • 它支援兩種Java API:Cypher API和Native Java API來開發Java應用程式

Neo4j的優點:

  • 它很容易表示連線的資料
  • 檢索/遍歷/導航更多的連線資料是非常容易和快速的
  • 它非常容易地表示半結構化資料
  • Neo4j CQL查詢語言命令是人性化的可讀格式,非常容易學習
  • 使用簡單而強大的資料模型
  • 它不需要複雜的連線來檢索連線的/相關的資料,因為它很容易檢索它的相鄰節點或關係細節沒有
    連線或索引

4.Neo4j資料模型

圖論基礎

  圖是一組節點和連線這些節點的關係,圖形以屬性的形式將資料儲存在節點和關係中,屬性是用於表示
資料的鍵值對。
  在圖論中,我們可以表示一個帶有圓的節點,節點之間的關係用一個箭頭標記表示。
最簡單的可能圖是單個節點:

image.png

我們可以使用節點表示社交網路(如Google+(GooglePlus)個人資料),它不包含任何屬性。向
Google+個人資料新增一些屬性:

image.png

在兩個節點之間建立關係:

image.png

此處在兩個配置檔案之間建立關係名稱“跟隨”。 這意味著 Profile-I 遵循 Profile-II。

屬性圖模型

Neo4j圖資料庫遵循屬性圖模型來儲存和管理其資料。

  • 屬性圖模型規則
  • 表示節點,關係和屬性中的資料
  • 節點和關係都包含屬性
  • 關係連線節點
  • 屬性是鍵值對
  • 節點用圓圈表示,關係用方向鍵表示。
  • 關係具有方向:單向和雙向。
  • 每個關係包含“開始節點”或“從節點”和“到節點”或“結束節點”

  在屬性圖資料模型中,關係應該是定向的。如果我們嘗試建立沒有方向的關係,那麼它將丟擲一個錯誤
訊息。在Neo4j中,關係也應該是有方向性的。如果我們嘗試建立沒有方向的關係,那麼Neo4j會丟擲一
個錯誤訊息,“關係應該是方向性的”。

  Neo4j圖資料庫將其所有資料儲存在節點和關係中,我們不需要任何額外的RDBMS資料庫或NoSQL資料
庫來儲存Neo4j資料庫資料,它以圖的形式儲存資料。Neo4j使用本機GPE(圖形處理引擎)來使用它的
本機圖儲存格式。
圖資料庫資料模型的主要構建塊是:

  • 節點
  • 關係
  • 屬性

簡單的屬性圖的例子:

image.png

  這裡我們使用圓圈表示節點。 使用箭頭表示關係,關係是有方向性的。 我們可以用Properties(鍵值
對)來表示Node的資料。 在這個例子中,我們在Node的Circle中表示了每個Node的Id屬性。

Neo4j的構建元素

Neo4j圖資料庫主要有以下構建元素:

  • 節點
  • 屬性
  • 關係
  • 標籤
  • 資料瀏覽器

image.png

有一個或多個標籤,用於描述其在圖表中的作用
屬性
  屬性(Property)是用於描述圖節點和關係的鍵值對。其中Key是一個字串,值可以透過使用任何

  • Neo4j資料型別來表示
  • 屬性是命名值,其中名稱(或鍵)是字串
  • 屬性可以被索引和約束
  • 可以從多個屬性建立複合索引

關係
  關係(Relationship)同樣是圖資料庫的基本元素。當資料庫中已經存在節點後,需要將節點連線起來
構成圖。關係就是用來連線兩個節點,關係也稱為圖論的邊(Edge) ,其始端和末端都必須是節點,關係不
能指向空也不能從空發起。關係和節點一樣可以包含多個屬性,但關係只能有一個型別(Type) 。
關係連線兩個節點
關係是方向性的
節點可以有多個甚至遞迴的關係
關係可以有一個或多個屬性(即儲存為鍵/值對的屬性)

基於方向性,Neo4j關係被分為兩種主要型別:

  • 單向關係
  • 雙向關係

標籤
  標籤(Label)將一個公共名稱與一組節點或關係相關聯, 節點或關係可以包含一個或多個標籤。 我們
可以為現有節點或關係建立新標籤, 我們可以從現有節點或關係中刪除標籤。
標籤用於將節點分組
一個節點可以具有多個標籤
對標籤進行索引以加速在圖中查詢節點
本機標籤索引針對速度進行了最佳化

Neo4j Browser
  一旦我們安裝Neo4j,我們就可以訪問Neo4j資料瀏覽器

image.png

5.軟體安裝

下載地址:https://neo4j.com/download-center/
安裝方式:

  • Neo4j Enterprise Server
  • Neo4j Community Server
  • Neo4j Desktop

下載相關軟體

image.png

解壓縮即可

image.png

相關的指令

console: 直接啟動 neo4j 伺服器
install-service | uninstall-service | update-service : 安裝/解除安裝/更新 neo4j 服務
start/stop/restart/status: 啟動/停止/重啟/狀態
-V 輸出更多資訊

進入到bin目錄,執行

neo4j console

在瀏覽器中訪問http://localhost:7474
使用使用者名稱neo4j和預設密碼neo4j進行連線,然後會提示更改密碼。
Neo4j Browser是開發人員用來探索Neo4j資料庫、執行Cypher查詢並以表格或圖形形式檢視結果的工
具。

image.png

當然也可以透過 Docker 來安裝

拉取映象

docker pull neo4j:3.5.22-community

執行映象

docker run -d -p 7474:7474 -p 7687:7687 --name neo4j \
-e "NEO4J_AUTH=neo4j/123456" \
-v /usr/local/soft/neo4j/data:/data \
-v /usr/local/soft/neo4j/logs:/logs \
-v /usr/local/soft/neo4j/conf:/var/lib/neo4j/conf \
-v /usr/local/soft/neo4j/import:/var/lib/neo4j/import \
neo4j:3.5.22-community

二、CQL語句

1.CQL簡介

  Neo4j的Cypher語言是為處理圖形資料而構建的,CQL代表Cypher查詢語言。像Oracle資料庫具有查詢
語言SQL,Neo4j具有CQL作為查詢語言。

  • 它是Neo4j圖形資料庫的查詢語言。
  • 它是一種宣告性模式匹配語言
  • 它遵循SQL語法。
  • 它的語法是非常簡單且人性化、可讀的格式。

image.png

2.CREATE 命令

Neo4j使用CQL“CREATE”命令

  • 建立沒有屬性的節點
  • 使用屬性建立節點
  • 在沒有屬性的節點之間建立關係
  • 使用屬性建立節點之間的關係
  • 為節點或關係建立單個或多個標籤

語法命令

CREATE (<node-name>:<label-name>)

語法說明

image.png

注意事項 -

1、Neo4j資料庫伺服器使用此<node-name>將此節點詳細資訊儲存在Database.As中作為Neo4j DBA或Developer,我們不能使用它來訪問節點詳細資訊。

2、Neo4j資料庫伺服器建立一個<label-name>作為內部節點名稱的別名。作為Neo4j DBA或Developer,我們應該使用此標籤名稱來訪問節點詳細資訊。

3.MATCH 命令

Neo4j CQL MATCH 命令用於

  • 從資料庫獲取有關節點和屬性的資料
  • 從資料庫獲取有關節點,關係和屬性的資料

語法格式:

MATCH 
(
   <node-name>:<label-name>
)

語法說明:

image.png

4.RETURN 子句

Neo4j CQL RETURN子句用於 -

  • 檢索節點的某些屬性
  • 檢索節點的所有屬性
  • 檢索節點和關聯關係的某些屬性
  • 檢索節點和關聯關係的所有屬性

語法結構

RETURN 
   <node-name>.<property1-name>,
   ........
   <node-name>.<propertyn-name>

語法說明:

image.png

5.MATCH和RETURN

在Neo4j CQL中,我們不能單獨使用MATCH或RETURN命令,因此我們應該合併這兩個命令以從資料庫檢索資料。

Neo4j使用CQL MATCH + RETURN命令 -

  • 檢索節點的某些屬性
  • 檢索節點的所有屬性
  • 檢索節點和關聯關係的某些屬性
  • 檢索節點和關聯關係的所有屬性

語法結構

MATCH Command
RETURN Command

語法說明

image.png

6.CREATE+MATCH+RETURN命令

先建立一個客戶

create (e:Customer {id:"1001",name:"boge",location:"cs"})

image.png

建立一個信用卡節點

create (cc:CreditCard {id:"9999",number:"1234567890",cvv:"888",expiredate:"22/17"})

image.png

然後我們可以查詢對應的資訊

match (k:customer) return k.name,k.location,k.id

image.png

還可以查詢信用卡的資訊

match (m:CreditCard) return m.number,m.cvv,m.id,m.expiredate

image.png

7.關係基礎

Neo4j圖資料庫遵循屬性圖模型來儲存和管理其資料。

根據屬性圖模型,關係應該是定向的。 否則,Neo4j將丟擲一個錯誤訊息。

基於方向性,Neo4j關係被分為兩種主要型別。

  • 單向關係
  • 雙向關係

在以下場景中,我們可以使用Neo4j CQL CREATE命令來建立兩個節點之間的關係。 這些情況適用於Uni和雙向關係。

  • 在兩個現有節點之間建立無屬性的關係
  • 在兩個現有節點之間建立有屬性的關係
  • 在兩個新節點之間建立無屬性的關係
  • 在兩個新節點之間建立有屬性的關係
  • 在具有WHERE子句的兩個退出節點之間建立/不使用屬性的關係

注意 -

我們將建立客戶和CreditCard之間的關係,如下所示:

image.png

8.CREATE建立標籤

CREATE標籤可以建立單個標籤或者多個標籤

CREATE(node-name:lable-name1:lable-name2)

還有就是可以根據CREATE語句來建立標籤之間的關係

CREATE (node1-name:lable1-name) - [relationship-name:relationship-lable-name]->(node2-name:lable2-name)

image.png

案例:

create (p1:Profile1)-[r1:喜歡]->(p2:Profile2)

image.png

9.WHERE子句

像SQL一樣,Neo4j CQL在CQL MATCH命令中提供了WHERE子句來過濾MATCH查詢的結果。

語法結構

WHERE <condition>

複雜的語法結構

WHERE <condition> <boolean-operator> <condition>

Neo4j支援以下布林運算子在Neo4j CQL WHERE子句中使用以支援多個條件。

image.png

Neo4j 支援以下的比較運算子,在 Neo4j CQL WHERE 子句中使用來支援條件。

image.png

案例:

match (m:Employee) where m.age > 18 or m.id = 1002  return m

image.png

多個節點關聯查詢

image.png

where子句也可以建立關係

語法結構

MATCH (<node1-label-name>:<node1-name>),(<node2-label-name>:<node2-name>) 
WHERE <condition>
CREATE (<node1-label-name>)-[<relationship-label-name>:<relationship-name>
       {<relationship-properties>}]->(<node2-label-name>) 

image.png

案例

match (c:customer) , (d:CreditCard) where c.id = "1001" and d.id = "9999" create (c)-[r:消費{shopdate:"2022/09/28",price:6000}]->(d) return r

image.png

10.DELETE命令

Neo4j使用CQL DELETE子句

  • 刪除節點。
  • 刪除節點及相關節點和關係。

對應的語法結構

DELETE <node-name-list>

image.png

注意 -

我們應該使用逗號(,)運算子來分隔節點名。

11.REMOVE命令

有時基於我們的客戶端要求,我們需要向現有節點或關係新增或刪除屬性。

我們使用Neo4j CQL SET子句向現有節點或關係新增新屬性。

我們使用Neo4j CQL REMOVE子句來刪除節點或關係的現有屬性

Neo4j CQL REMOVE命令用於

  • 刪除節點或關係的標籤
  • 刪除節點或關係的屬性

Neo4j CQL DELETE和REMOVE命令之間的主要區別 -

  • DELETE操作用於刪除節點和關聯關係。
  • REMOVE操作用於刪除標籤和屬性。

Neo4j CQL DELETE和REMOVE命令之間的相似性 -

  • 這兩個命令不應單獨使用。
  • 兩個命令都應該與MATCH命令一起使用。

image.png

透過remove來移除標籤

match (d:`電影`) remove d:Movie

image.png

12.SET子句

有時,根據我們的客戶端要求,我們需要向現有節點或關係新增新屬性。

要做到這一點,Neo4j CQL 提供了一個SET子句。

Neo4j CQL 已提供 SET 子句來執行以下操作。

  • 向現有節點或關係新增新屬性
  • 新增或更新屬性值

語法結構

SET  <property-name-list>

image.png

新增屬性:

MATCH (book:Book)
SET book.title = 'superstar'
RETURN book

image.png

image.png

13.ORDER BY排序

Neo4j CQL在MATCH命令中提供了“ORDER BY”子句,對MATCH查詢返回的結果進行排序。

我們可以按升序或降序對行進行排序。

預設情況下,它按升序對行進行排序。 如果我們要按降序對它們進行排序,我們需要使用DESC子句。

語法結構

ORDER BY  <property-name-list>  [DESC]	 

image.png

舉例:

MATCH (emp:Employee)
RETURN emp.empid,emp.name,emp.salary,emp.deptno
ORDER BY emp.name

image.png

14.UNION合併

與SQL一樣,Neo4j CQL有兩個子句,將兩個不同的結果合併成一組結果

  • UNION
  • UNION ALL

UNION子句

它將兩組結果中的公共行組合並返回到一組結果中。 它不從兩個節點返回重複的行。

限制:

結果列型別和來自兩組結果的名稱必須匹配,這意味著列名稱應該相同,列的資料型別應該相同。

語法結構

<MATCH Command1>
   UNION
<MATCH Command2>

image.png

注意 -

如果這兩個查詢不返回相同的列名和資料型別,那麼它丟擲一個錯誤。

as 來處理不同的字首

image.png

MATCH (cc:CreditCard)
RETURN cc.id as id,cc.number as number,cc.name as name,
   cc.valid_from as valid_from,cc.valid_to as valid_to
UNION
MATCH (dc:DebitCard)
RETURN dc.id as id,dc.number as number,dc.name as name,
   dc.valid_from as valid_from,dc.valid_to as valid_to

UNION ALL子句

它結合並返回兩個結果集的所有行成一個單一的結果集。它還返回由兩個節點重複行。

限制

結果列型別,並從兩個結果集的名字必須匹配,這意味著列名稱應該是相同的,列的資料型別應該是相同的。

union all 語法

<MATCH Command1>
UNION ALL
<MATCH Command2>

image.png

15.LIMIT和SKIP子句

Neo4j CQL已提供“LIMIT”子句來過濾或限制查詢返回的行數。 它修剪CQL查詢結果集底部的結果。

如果我們要修整CQL查詢結果集頂部的結果,那麼我們應該使用CQL SKIP子句

image.png

skip跳過

image.png

skip和limit可以結合使用達到分頁的效果

image.png

16.合併

Neo4j使用CQL MERGE命令 -

  • 建立節點,關係和屬性
  • 為從資料庫檢索資料

MERGE命令是CREATE命令和MATCH命令的組合。

MERGE = CREATE + MATCH

merge語法

MERGE (<node-name>:<label-name>
{
   <Property1-name>:<Pro<rty1-Value>
   .....
   <Propertyn-name>:<Propertyn-Value>
})

image.png

注意 -

Neo4j CQL MERGE命令語法與CQL CREATE命令類似。

image.png

17.NULL值

Neo4j CQL將空值視為對節點或關係的屬性的缺失值或未定義值。

當我們建立一個具有現有節點標籤名稱但未指定其屬性值的節點時,它將建立一個具有NULL屬性值的新節點。

image.png

還可以用null 作為查詢的條件

image.png

18.IN運算子

與SQL一樣,Neo4j CQL提供了一個IN運算子,以便為CQL命令提供值的集合。

IN[<Collection-of-values>]

案例:

MATCH (e:Employee) 
WHERE e.id IN [123,124]
RETURN e.id,e.name,e.sal,e.deptno

image.png

三、CQL函式

1.字串函式

與SQL一樣,Neo4J CQL提供了一組String函式,用於在CQL查詢中獲取所需的結果。

列舉幾個常用的

image.png

案例:

image.png

image.png

2.AGGEGATION聚合

和SQL一樣,Neo4j CQL提供了一些在RETURN子句中使用的聚合函式。 它類似於SQL中的GROUP BY子句。

我們可以使用MATCH命令中的RETURN +聚合函式來處理一組節點並返回一些聚合值。

image.png

image.png

3.關係函式

Neo4j CQL提供了一組關係函式,以在獲取開始節點,結束節點等細節時知道關係的細節。

image.png

案例:

image.png

image.png

四、Neo4J和SpringBoot整合

新增對應的依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-neo4j</artifactId>
        </dependency>

然後新增對應的配置檔案

# neo4j配置
spring.data.neo4j.uri= bolt://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=123456

1.Node的操作

然後建立對應的實體物件

@Data
@NodeEntity("Person")
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    @Property("name")
    private String name;
}

@NodeEntity:標明是一個節點實體

@RelationshipEntity:標明是一個關係實體

@Id:實體主鍵

@Property:實體屬性

@GeneratedValue:實體屬性值自增

@StartNode:開始節點(可以理解為父節點)

@EndNode:結束節點(可以理解為子節點)

然後建立對應的Repository介面

@Repository
public interface PersonRepository extends Neo4jRepository<Person,Long> {
}

然後我們就可以測試Node的建立了

    @Autowired
    private PersonRepository personRepository;

    @Test
    void contextLoads() {
        Person person = new Person();
        person.setName("波哥");
        personRepository.save(person);
    }

建立成功

image.png

2.Node關係的維護

建立關係實體

@Data
@RelationshipEntity(type = "徒弟")
public class PersonRelation implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    @StartNode
    private Person parent;

    @EndNode
    private Person child;

    @Property
    private String relation;

    public PersonRelation(Person parent, Person child, String relation) {
        this.parent = parent;
        this.child = child;
        this.relation = relation;
    }
}

建立對應的Dao持久層

@Repository
public interface PersonRelationRepository extends Neo4jRepository<PersonRelation,Long> {

}

然後測試

    /**
     * 節點關係
     */
    @Test
    void nodeRelation(){
        Person p1 = new Person("唐僧",6666);
        Person p2 = new Person("孫悟空",5555);
        Person p3 = new Person("豬八戒",3333);
        Person p4 = new Person("沙僧",2222);
        Person p5 = new Person("白龍馬",1111);

        // 維護 關係
        PersonRelation pr1 = new PersonRelation(p1,p2,"徒弟");
        PersonRelation pr2 = new PersonRelation(p1,p3,"徒弟");
        PersonRelation pr3 = new PersonRelation(p1,p4,"徒弟");
        PersonRelation pr4 = new PersonRelation(p1,p5,"徒弟");

        personRelationRepository.save(pr1);
        personRelationRepository.save(pr2);
        personRelationRepository.save(pr3);
        personRelationRepository.save(pr4);

    }

執行後的效果:

image.png

相關文章