Spring?JPA聯(lián)表查詢之注解屬性詳解
前言
對于聯(lián)表查詢的四個注解 @OneToOne
、@OneToMany
、@ManyToOne
和 @ManyToMany
,他們有幾個用得比較多的屬性需要了解一下。
一、targetEntity
(可選)指定關聯(lián)的實體類;默認為當前標注的實體類。
@JoinColumn(name = "car_id") @OneToOne(fetch = FetchType.LAZY, targetEntity = Car.class) private Car car;
二、cascade
(可選)當前類對象操作后級聯(lián)對象的操作。默認為不級聯(lián)任何操作。
1、不定義
只對作用的實體類有影響,對級聯(lián)對象不會產生任何影響
2、CascadeType.PERSIST
級聯(lián)新建。對父對象進行持久化,同時對子對象也相應的持久化。
user 實體類中關聯(lián)的對象字段(級聯(lián)對象)
@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í)行請求 /user/save?name=lala&age=21&carname=蘇M00002
,控制臺打印如下:
Hibernate: insert into user (age, car_id, name) values (?, ?, ?) Hibernate: update car set name=?, user_id=? where id=?
如果有級聯(lián)新建(保存)的需求,只能使用 CascadeType.PERSIST
或者 CascadeType.ALL
,使用其他的操作會報錯。
3、CascadeType.REMOVE
級聯(lián)刪除。刪除數(shù)據(jù)庫中的對應實體,同時刪除對應的所有關聯(lián)對象
user 實體類中關聯(lián)的對象字段(級聯(lián)對象)
@JoinColumn(name = "car_id") @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) @JsonIgnore private Car car;
service 層刪除方法
/** * 通過id進行刪除數(shù)據(jù) * @param id */ @GetMapping("/deleteById") public void deleteById(Integer id){ userService.deleteById(id); }
執(zhí)行請求 /user/deleteById?id=17
,控制臺打印如下:
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]
如果有級聯(lián)刪除的需求,只能使用 CascadeType.REMOVE
或者 CascadeType.ALL
;使用其他的雖然不會報錯,但是只會對作用對象進行刪除,相關聯(lián)的數(shù)據(jù)不會進行刪除。
4、CascadeType.REFRESH
級聯(lián)刷新。作用對象 refresh
的同時級聯(liá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ù)庫中刷新實例的狀態(tài),覆蓋對實體所做的更改(如果有的話)
;通俗講就是,只要沒有做持久化的數(shù)據(jù)更改,就得不到我的認可。
5、CascadeType.MERGE
級聯(lián)更新。
user 實體類中關聯(lián)的對象字段(級聯(lián)對象)
@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í)行請求/user/save?id=1&name=kiki&age=33&carid=1&carname=蘇M00003
,控制臺打印如下:
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]
可以更新所有級聯(lián)的對象,但是前提是要提供對象的 id,否則系統(tǒng)會認為你是新增。
6、CascadeType.ALL
表示同時選擇 CascadeType.PERSIST
、CascadeType.REMOVE
、CascadeType.REFRESH
和 CascadeType.MERGE
。一般情況不會使用,因為 CascadeType.REMOVE
是個高危操作。
三、fetch
(可選)關聯(lián)是否延遲加載(懶加載 FetchType.LAZY
)或者立刻加載(FetchType.EAGER
)。立刻加載是立刻獲取關聯(lián)的實體;延遲加載(懶加載)是表示關系類在被訪問時才加載。
FetchType.LAZY
User 實體類上的 Car 屬性中 @OneToOne
添加屬性 fetch = FetchType.LAZY
(這里有一個報錯需要注意一下,詳情請見 # Spring JPA 錯題集 第一個信息)
@OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "car_id") 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=? [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]
這里先挖一個坑,就是 JPA 在讀取數(shù)據(jù)時 N+1 的問題。
FetchType.EAGER
再看看立刻加載的場景。
執(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_, 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]
懶加載的時候(LAZY)只會將主體數(shù)據(jù)請求出來,對于級聯(lián)數(shù)據(jù)需要我們主動 get,如下圖所示:
而立刻加載的時候(EAGER)會將主體數(shù)據(jù)和所有級聯(lián)數(shù)據(jù)請求出來,對于大數(shù)據(jù)的情況,系統(tǒng)可能會存在一定的壓力,所以實際項目中,我們大多數(shù)情況下會使用 FetchType.LAZY
。
四、mappedBy
(可選)擁有關聯(lián)關系的域,如果關系是單向的就不需要;如果是雙向關系表,那么擁有關系的這一方有建立、解除和更新與另一方關系的能力,而另一方?jīng)]有,只能被動管理,這個屬性被定義在關系的被擁有方
五、orphanRemoval
(可選)是否將刪除操作應用于具有已從關系中刪除,并將刪除操作級聯(lián)到這些實體;默認為false。
以上就是Spring JPA聯(lián)表查詢之注解屬性詳解的詳細內容,更多關于Spring JPA聯(lián)表查詢注解屬性的資料請關注腳本之家其它相關文章!
相關文章
Java基于MySQL實現(xiàn)學生管理系統(tǒng)
這篇文章主要為大家詳細介紹了Java基于MySQL實現(xiàn)學生管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01maven創(chuàng)建spark項目的pom.xml文件配置demo
這篇文章主要為大家介紹了maven創(chuàng)建spark項目的pom.xml文件配置demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-05-05在RedHat系統(tǒng)上安裝JDK與Tomcat的步驟
這篇文章主要介紹了在RedHat系統(tǒng)上安裝Java與Tomcat的步驟,同樣適用于CentOS等RedHat系的Linux系統(tǒng),需要的朋友可以參考下2015-11-11