Spring?JPA聯(lián)表查詢之注解屬性詳解
前言
對(duì)于聯(lián)表查詢的四個(gè)注解 @OneToOne、@OneToMany、@ManyToOne 和 @ManyToMany,他們有幾個(gè)用得比較多的屬性需要了解一下。
一、targetEntity
(可選)指定關(guān)聯(lián)的實(shí)體類;默認(rèn)為當(dāng)前標(biāo)注的實(shí)體類。
@JoinColumn(name = "car_id") @OneToOne(fetch = FetchType.LAZY, targetEntity = Car.class) private Car car;
二、cascade
(可選)當(dāng)前類對(duì)象操作后級(jí)聯(lián)對(duì)象的操作。默認(rèn)為不級(jí)聯(lián)任何操作。
1、不定義
只對(duì)作用的實(shí)體類有影響,對(duì)級(jí)聯(lián)對(duì)象不會(huì)產(chǎn)生任何影響
2、CascadeType.PERSIST
級(jí)聯(lián)新建。對(duì)父對(duì)象進(jìn)行持久化,同時(shí)對(duì)子對(duì)象也相應(yīng)的持久化。
user 實(shí)體類中關(guān)聯(lián)的對(duì)象字段(級(jí)聯(lián)對(duì)象)
@JoinColumn(name = "car_id") @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @JsonIgnore private Car car;
service 層新建方法
@GetMapping("/save")
public User save(String name, Integer age, String carname) {
User user = new User();
user.setName(name);
user.setAge(age);
Car car = new Car();
car.setName(carname);
car.setUser(user);
user.setCar(car);
return userService.save(user);
}
執(zhí)行請(qǐng)求 /user/save?name=lala&age=21&carname=蘇M00002,控制臺(tái)打印如下:
Hibernate:
insert
into
user
(age, car_id, name)
values
(?, ?, ?)
Hibernate:
update
car
set
name=?,
user_id=?
where
id=?
如果有級(jí)聯(lián)新建(保存)的需求,只能使用 CascadeType.PERSIST 或者 CascadeType.ALL,使用其他的操作會(huì)報(bào)錯(cuò)。
3、CascadeType.REMOVE
級(jí)聯(lián)刪除。刪除數(shù)據(jù)庫中的對(duì)應(yīng)實(shí)體,同時(shí)刪除對(duì)應(yīng)的所有關(guān)聯(lián)對(duì)象
user 實(shí)體類中關(guān)聯(lián)的對(duì)象字段(級(jí)聯(lián)對(duì)象)
@JoinColumn(name = "car_id") @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) @JsonIgnore private Car car;
service 層刪除方法
/**
* 通過id進(jìn)行刪除數(shù)據(jù)
* @param id
*/
@GetMapping("/deleteById")
public void deleteById(Integer id){
userService.deleteById(id);
}
執(zhí)行請(qǐng)求 /user/deleteById?id=17,控制臺(tái)打印如下:
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=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [17]
Hibernate:
select
car0_.id as id1_0_0_,
car0_.name as name2_0_0_,
car0_.user_id as user_id3_0_0_
from
car car0_
where
car0_.id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [5]
Hibernate:
update
car
set
name=?,
user_id=?
where
id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [蘇M00001]
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [INTEGER] - [null]
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [INTEGER] - [5]
Hibernate:
delete
from
user
where
id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [17]
Hibernate:
delete
from
car
where
id=?
[nio-7777-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [5]
如果有級(jí)聯(lián)刪除的需求,只能使用 CascadeType.REMOVE 或者 CascadeType.ALL;使用其他的雖然不會(huì)報(bào)錯(cuò),但是只會(huì)對(duì)作用對(duì)象進(jìn)行刪除,相關(guān)聯(lián)的數(shù)據(jù)不會(huì)進(jìn)行刪除。
4、CascadeType.REFRESH
級(jí)聯(lián)刷新。作用對(duì)象 refresh 的同時(shí)級(jí)聯(lián)對(duì)象也進(jìn)行 refresh。這里 refresh 方法是EntityManager 的方法,我們來看一下他的源碼
/** * Refresh the state of the instance from the database, * overwriting changes made to the entity, if any. * @param entity entity instance * @throws IllegalArgumentException if the instance is not * an entity or the entity is not managed * @throws TransactionRequiredException if there is no * transaction when invoked on a container-managed * entity manager of type <code>PersistenceContextType.TRANSACTION</code> * @throws EntityNotFoundException if the entity no longer * exists in the database */ public void refresh(Object entity);
最主要的是從數(shù)據(jù)庫中刷新實(shí)例的狀態(tài),覆蓋對(duì)實(shí)體所做的更改(如果有的話);通俗講就是,只要沒有做持久化的數(shù)據(jù)更改,就得不到我的認(rèn)可。
5、CascadeType.MERGE
級(jí)聯(lián)更新。
user 實(shí)體類中關(guān)聯(lián)的對(duì)象字段(級(jí)聯(lián)對(duì)象)
@JoinColumn(name = "car_id") @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) @JsonIgnore private Car car;
service 層更新方法
@GetMapping("/save")
public User save(Integer id, String name, Integer age, Integer carid, String carname) {
User user = new User();
if (id != null) user.setId(id);
user.setName(name);
user.setAge(age);
Car car = new Car();
if (carid != null) car.setId(carid);
car.setName(carname);
car.setUser(user);
user.setCar(car);
return userService.save(user);
}
執(zhí)行請(qǐng)求/user/save?id=1&name=kiki&age=33&carid=1&carname=蘇M00003,控制臺(tái)打印如下:
Hibernate:
select
user0_.id as id1_2_1_,
user0_.age as age2_2_1_,
user0_.car_id as car_id4_2_1_,
user0_.name as name3_2_1_,
car1_.id as id1_0_0_,
car1_.name as name2_0_0_,
car1_.user_id as user_id3_0_0_
from
user user0_
left outer join
car car1_
on user0_.car_id=car1_.id
where
user0_.id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
Hibernate:
update
car
set
name=?,
user_id=?
where
id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [蘇M00003]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [INTEGER] - [1]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [INTEGER] - [1]
Hibernate:
update
user
set
age=?,
car_id=?,
name=?
where
id=?
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [33]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [INTEGER] - [1]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [kiki]
[io-7777-exec-10] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [INTEGER] - [1]
可以更新所有級(jí)聯(lián)的對(duì)象,但是前提是要提供對(duì)象的 id,否則系統(tǒng)會(huì)認(rèn)為你是新增。
6、CascadeType.ALL
表示同時(shí)選擇 CascadeType.PERSIST、CascadeType.REMOVE、CascadeType.REFRESH 和 CascadeType.MERGE。一般情況不會(huì)使用,因?yàn)?CascadeType.REMOVE 是個(gè)高危操作。
三、fetch
(可選)關(guān)聯(lián)是否延遲加載(懶加載 FetchType.LAZY)或者立刻加載(FetchType.EAGER)。立刻加載是立刻獲取關(guān)聯(lián)的實(shí)體;延遲加載(懶加載)是表示關(guān)系類在被訪問時(shí)才加載。
FetchType.LAZY
User 實(shí)體類上的 Car 屬性中 @OneToOne 添加屬性 fetch = FetchType.LAZY(這里有一個(gè)報(bào)錯(cuò)需要注意一下,詳情請(qǐng)見 # Spring JPA 錯(cuò)題集 第一個(gè)信息)
@OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "car_id") private Car car;
執(zhí)行請(qǐng)求/user/findById?id=1,控制臺(tái)打印如下:
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=?
[nio-7777-exec-1] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
Hibernate:
select
car0_.id as id1_0_0_,
car0_.name as name2_0_0_
from
car car0_
where
car0_.id=?
[nio-7777-exec-1] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
這里先挖一個(gè)坑,就是 JPA 在讀取數(shù)據(jù)時(shí) N+1 的問題。
FetchType.EAGER
再看看立刻加載的場景。
執(zhí)行請(qǐng)求/user/findById?id=1,控制臺(tái)打印如下:
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_,
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=?
[nio-7777-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
懶加載的時(shí)候(LAZY)只會(huì)將主體數(shù)據(jù)請(qǐng)求出來,對(duì)于級(jí)聯(lián)數(shù)據(jù)需要我們主動(dòng) get,如下圖所示:

而立刻加載的時(shí)候(EAGER)會(huì)將主體數(shù)據(jù)和所有級(jí)聯(lián)數(shù)據(jù)請(qǐng)求出來,對(duì)于大數(shù)據(jù)的情況,系統(tǒng)可能會(huì)存在一定的壓力,所以實(shí)際項(xiàng)目中,我們大多數(shù)情況下會(huì)使用 FetchType.LAZY。
四、mappedBy
(可選)擁有關(guān)聯(lián)關(guān)系的域,如果關(guān)系是單向的就不需要;如果是雙向關(guān)系表,那么擁有關(guān)系的這一方有建立、解除和更新與另一方關(guān)系的能力,而另一方?jīng)]有,只能被動(dòng)管理,這個(gè)屬性被定義在關(guān)系的被擁有方
五、orphanRemoval
(可選)是否將刪除操作應(yīng)用于具有已從關(guān)系中刪除,并將刪除操作級(jí)聯(lián)到這些實(shí)體;默認(rèn)為false。
以上就是Spring JPA聯(lián)表查詢之注解屬性詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring JPA聯(lián)表查詢注解屬性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java基于MySQL實(shí)現(xiàn)學(xué)生管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java基于MySQL實(shí)現(xiàn)學(xué)生管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
maven創(chuàng)建spark項(xiàng)目的pom.xml文件配置demo
這篇文章主要為大家介紹了maven創(chuàng)建spark項(xiàng)目的pom.xml文件配置demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
在RedHat系統(tǒng)上安裝JDK與Tomcat的步驟
這篇文章主要介紹了在RedHat系統(tǒng)上安裝Java與Tomcat的步驟,同樣適用于CentOS等RedHat系的Linux系統(tǒng),需要的朋友可以參考下2015-11-11
springcloud之自定義簡易消費(fèi)服務(wù)組件
這篇文章主要介紹了springcloud之自定義簡易消費(fèi)服務(wù)組件,本篇來使用rest+ribbon消費(fèi)服務(wù),并且通過輪詢方式來自定義了個(gè)簡易消費(fèi)組件,感興趣的小伙伴們可以參考一下2018-06-06
Java中JDBC連接池的基本原理及實(shí)現(xiàn)方式
本文詳細(xì)講解了Java中JDBC連接池的基本原理及實(shí)現(xiàn)方式,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
判斷以逗號(hào)分隔的字符串中是否包含某個(gè)數(shù)的實(shí)例
下面小編就為大家?guī)硪黄袛嘁远禾?hào)分隔的字符串中是否包含某個(gè)數(shù)的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11

