Udemy Course Spring JPA 18

One to One & Mapping

ZONGRU Li
7 min readApr 30, 2019

如何建立One to One的關係?

以Student與Passport為例

我們需要再建立兩個間互相關聯之欄位

Student:

passport_id為40001者屬於Pig

Passport:

student_id為20001對應Passport number:E123456

於程式上則是如斯改寫,Student內加入Passport屬性

此時直接執行DemoApplication

程式反而另建passport_id

就算我們data.sql也沒給第三個欄位值

所以我們可以補上data.sql

再次執行DemoApplication得執行失敗

因為前面也有看到有建了FK(foreign key)

所以問題其實出在data.sql的執行順序

passport要先INSERT完再INSERT student

改為如下

再執行一次即正常

直接在H2-console上跑SQL:

SELECT * FROM STUDENT, PASSPORT
WHERE STUDENT.PASSPORT_ID=PASSPORT.ID

Student的passport_id是FK,對應passport的id(自己的PK)

所以當然要先建好passport才能關聯過來

以上即為OnetoOne關聯

相關專案放置於"SpringJPA深入OnetoOne"

OneToOne Mapping

目前專案如下

接著複製CourseRepository為StudentRepository

用ctrl+F的取代功能並勾選區別大小寫,將Course改寫成Student

再改首字母小寫的

然後先到Student.java內新增passport的get setter

回到StudentRepository

改寫playWithEntityManager Method名稱為saveStudentWithPassport

並改寫其內容

所以目前Student.java如下

StudentRepository.java變為如下

接著讓DemoApplication使用上面改好的Method

執行得:

一個TransientPropertyValueException

意即我們準備透過Student這個Entity要save(INSERT) 一筆Passport

但是當下Passport還沒ready在DB內!!

什麼意思呢?

將方法改寫為以下:

可用deBug mode觀看情況

DemoApplication再一般執行得

正常的INSERT(先Passport再Student)

http://localhost:8090/h2-console

資料正常!!

專案存於”SpringJPA深入OnetoOneMapping”

實際寫Test code測試

並在下方紅框設中斷點

用deBug mode可以觀察到如下

Spring JPA替我們生出了left outer join來關聯

student0_.passport_id=passport1_.id

繼續往下執行看到

上面出現Course是因為Student的toString忘了改

這個結論為:

我們只是要取得student這個entity

預期的student為[id=20001,name=Pig,Passport]

但是請注意紅框處

然而程式幫我們取得到了整個完整的passport內容

所以取到的student為[id=20001,name=Pig,Passport[id=40001,number=E123456]]

我們稱此為” eager fetch”

在某些情況下這將會造成效能問題

(我明明只想看到student的資料,不想連同passport也看到)

解決辦法為,來到Student.java改寫

再重跑StudentRepositoryTest會看到

一開始取得student entity的SQL語句

上面的no session是在執行student.getPassport()時出錯

其原因是因為:

當Student student = em.find(Student.class, 20001L);執行後

transaction即結束!!!

接著我們單純印出student(已透過上面的交易拿到entity)沒問題

所以尚缺一個transaction供student.getPassport()印出passport的詳細資料

所以加入以下annotation,讓spring管理交易

再執行得正常之結果

所以LAZY FETCH就是指,在我想要(entity)的時候才拿

請程式不要自己就拿(entity)

目前專案置於"SpringJPA深入LAZY_FETCH"

(也就是Spring JPA預設走eager fetch,要用lazy要另外指定)

--

--

ZONGRU Li
ZONGRU Li

Written by ZONGRU Li

2022/11/17 開源部分個人筆記給LINE "Java程式語言討論區"社群,希望能對社群的技術學習做一點點貢獻.(掩面....記得退訂閱!

No responses yet