於程式上則是如斯改寫,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
繼續往下執行看到
這個結論為:
我們只是要取得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會看到
上面的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要另外指定)