Spring JPA聯(lián)表查詢之OneToOne源碼詳解
前言
前面幾篇我們學(xué)習(xí)的都是單表查詢,就是對一張表中的數(shù)據(jù)進行查詢。而實際項目中,基本都會有多張表聯(lián)合查詢的情況,今天我們就來了解下JPA的聯(lián)表查詢是如做的。
源碼
@OneToOne 注解實現(xiàn)一對一關(guān)系映射。比如用戶跟車輛的關(guān)系(這里假設(shè)一個人只能有一輛車),一個用戶只能對應(yīng)一輛車,而一輛車同樣只能對應(yīng)一個用戶。
老規(guī)矩,在實例之前,我們先看看源碼:
public @interface OneToOne { Class targetEntity() default void.class; CascadeType[] cascade() default {}; FetchType fetch() default EAGER; String mappedBy() default ""; boolean orphanRemoval() default false; }
注解屬性
- targetEntity:(可選)表示默認關(guān)聯(lián)的實體類型,默認為當(dāng)前標注的實體類
- cascade:(可選)當(dāng)前類對象操作后級聯(lián)對象的操作。默認為不級聯(lián)任何操作。
- fetch:(可選)關(guān)聯(lián)是否延遲加載或者立刻加載。立刻加載是立刻獲取關(guān)聯(lián)的實體;延遲加載是表示關(guān)系類在被訪問時才加載。默認值EAGER,也就是立刻加載。
- mappedBy:(可選)擁有關(guān)聯(lián)關(guān)系的域,如果關(guān)系是單向的就不需要;如果是雙向關(guān)系表,那么擁有關(guān)系的這一方有建立、解除和更新與另一方關(guān)系的能力,而另一方?jīng)]有,只能被動管理,這個屬性被定義在關(guān)系的被擁有方
- orphanRemoval:(可選)是否將刪除操作應(yīng)用于具有已從關(guān)系中刪除,并將刪除操作級聯(lián)到這些實體。
單向聯(lián)表
我這里所說的單向聯(lián)表就是只有一方添加注解;通俗講就是我可以通過 user 獲取到其 car 的信息,而不同通過 car 獲取到其 user 的信息。
user 實體類
@Entity @Data public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private int age; @OneToOne @JoinColumn(name = "car_id") private Car car; }
car 實體類
@Data @Entity public class Car { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; }
執(zhí)行請求 /user/findById?id=1
,控制臺打印如下:
Hibernate: select user0_.id as id1_1_0_, user0_.age as age2_1_0_, user0_.car_id as car_id4_1_0_, user0_.name as name3_1_0_, car1_.id as id1_0_1_, car1_.name as name2_0_1_ from user user0_ left outer join car car1_ on user0_.car_id=car1_.id where user0_.id=?
查詢結(jié)果
Optional[User(id=1, name=lili, age=11, car=Car(id=1, name=蘇A00001))]
從上面的 JPQL 語句我們可以發(fā)現(xiàn),uer 表 和 car 表 是通過left outer jion
進行連接的。這樣我們可以通過查詢 user 信息來獲取其使用的 car 信息。
雙向聯(lián)表
我們除了需要通過 user 信息來獲取其 car 信息為,有時還需要通過 car 信息來獲取其 user 信息。只要再在 car 的實體中添加 user 字段,并添加@OneToOne
注解。(這里有一個堆棧溢出的問題需要注意一下,詳情請見 JPA 錯題集 第二個報錯信息)
user 實體
@Entity @Data public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private int age; @OneToOne @JoinColumn(name = "car_id") @JsonIgnore private Car car; }
car 實體
@Entity @Data public class Car { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; @OneToOne @JoinColumn(name = "user_id") @JsonIgnore private User user; }
執(zhí)行請求 /car/findById?id=1
,控制臺打印如下:
Hibernate: select car0_.id as id1_0_0_, car0_.name as name2_0_0_, car0_.user_id as user_id3_0_0_, user1_.id as id1_2_1_, user1_.age as age2_2_1_, user1_.car_id as car_id4_2_1_, user1_.name as name3_2_1_, car2_.id as id1_0_2_, car2_.name as name2_0_2_, car2_.user_id as user_id3_0_2_ from car car0_ left outer join user user1_ on car0_.user_id=user1_.id left outer join car car2_ on user1_.car_id=car2_.id where car0_.id=?
查詢結(jié)果
Optional[Car(id=1, name=蘇A00001, user=com.example.sbjdemo.pojo.User@1c0775ea)]
用戶信息可以通過后面的實體類獲取
延遲加載(懶加載)
上面是 OneToOne 的情形,所以請求出來的數(shù)據(jù)也是比較有限的。試想一下,如果是 OneToMany,而我們只想獲取 one 的信息,但是 many 的數(shù)據(jù)卻跟著一起請求出來的,無論是從數(shù)據(jù)上還是性能上來講,都是一種負擔(dān)。那么,有沒有一種方法,讓我們能夠只獲取 one 的信息,而對于 many 可以動態(tài)獲取呢?這時,我們想到了源碼中一個 fetch 方法,他好像可以使用 LAZY 屬性來控制數(shù)據(jù)懶加載。廢話少說,上碼。
user 實體
User 實體類上的 Car 屬性中 @OneToOne
添加屬性 fetch = FetchType.LAZY
@OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "car_id") @JsonIgnore private Car car;
執(zhí)行請求 /user/findById?id=1
,控制臺打印如下:
Hibernate: select user0_.id as id1_2_0_, user0_.age as age2_2_0_, user0_.car_id as car_id4_2_0_, user0_.name as name3_2_0_ from user user0_ where user0_.id=?
查詢結(jié)果:
Optional[com.example.sbjdemo.pojo.User@30c311e6]
通過控制臺可以看出,只有一個用戶查詢的 sql,結(jié)果也就是一個 user 的實體類數(shù)據(jù)。那我們的 car 信息該如何查看呢?其實我們可以使用查詢結(jié)果 result 去 get 我們所需要的數(shù)據(jù),如下圖所示:
查詢完會發(fā)現(xiàn),控制臺又打印了一個 JPQL:
Hibernate: select car0_.id as id1_0_0_, car0_.name as name2_0_0_, car0_.user_id as user_id3_0_0_, user1_.id as id1_2_1_, user1_.age as age2_2_1_, user1_.car_id as car_id4_2_1_, user1_.name as name3_2_1_ from car car0_ left outer join user user1_ on car0_.user_id=user1_.id where car0_.id=?
恍然大悟,原來還是通過 sql 去完成的。
最后結(jié)論
oneToOne 主要針對一對一的場景,他們雙方都可以作為維護端或者被維護端,所以 mappedBy 這個屬性可有可無。這也要是與其他三個映射關(guān)系不同的地方。
以上就是Spring JPA聯(lián)表查詢之OneToOne源碼詳解的詳細內(nèi)容,更多關(guān)于Spring JPA聯(lián)表查詢的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
myatisplus的saveOrUpdate的提交總是update問題
這篇文章主要介紹了myatisplus的saveOrUpdate的提交總是update問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11HandlerMapping之RequestMappingHandlerMapping作用詳解
這篇文章主要介紹了HandlerMapping之RequestMappingHandlerMapping作用詳解,HandlerMapping是用來尋找Handler的,并不與Handler的類型或者實現(xiàn)綁定,而是根據(jù)需要定義的,那么為什么要單獨給@RequestMapping實現(xiàn)一個HandlerMapping,需要的朋友可以參考下2023-10-10使用springboot跳轉(zhuǎn)到指定頁面和(重定向,請求轉(zhuǎn)發(fā)的實例)
這篇文章主要介紹了使用springboot跳轉(zhuǎn)到指定頁面和(重定向,請求轉(zhuǎn)發(fā)的實例),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12Spring數(shù)據(jù)庫連接池url參數(shù)踩坑及解決
這篇文章主要介紹了Spring數(shù)據(jù)庫連接池url參數(shù)踩坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09使用SpringBoot動態(tài)切換數(shù)據(jù)源的實現(xiàn)方式
在我們企業(yè)項目開發(fā)的過程中,有的時候,一個項目需要在運行時,根據(jù)某種條件選擇使用哪個數(shù)據(jù)源,那么此時該怎么進行動態(tài)切換呢,本文給大家例舉一種常見的實現(xiàn)方式,文中有詳細的實現(xiàn)步驟,需要的朋友可以參考下2023-12-12java 中Executor, ExecutorService 和 Executors 間的不同
這篇文章主要介紹了java 中Executor, ExecutorService 和 Executors 間的不同的相關(guān)資料,需要的朋友可以參考下2017-06-06