jpa?onetomany?使用級(jí)連表刪除被維護(hù)表數(shù)據(jù)時(shí)的坑
jpa onetomany 使用級(jí)連表刪除被維護(hù)表數(shù)據(jù)時(shí)的坑
一、異常產(chǎn)生的場(chǎng)景
兩個(gè)實(shí)體類,為一對(duì)多的關(guān)系
主表 ,字段維護(hù)表,1個(gè)用戶可能有多個(gè)角色
實(shí)體類User,代碼如下:
package ywcai.ls.entity; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.Table; @Entity @Table(name="user") public class User implements Serializable{ /** * */ private static final long serialVersionUID = -7383132326629943397L; @Id @GeneratedValue(strategy= GenerationType.AUTO) @Column(name="id") private Long id; @Column(name="username") private String username; @Column(name="password") private String password; @OneToMany(cascade={CascadeType.ALL},fetch=FetchType.EAGER,mappedBy="user") //特別注意:onetomany標(biāo)識(shí)這是級(jí)聯(lián)1對(duì)多的關(guān)系。cascade={CascadeType.ALL}表示主表的增查刪改都會(huì)直接通過(guò)關(guān)聯(lián)字段對(duì)從表進(jìn)行相應(yīng)操作。 //例如刪除主表的一個(gè)user實(shí)例,從表與user相關(guān)聯(lián)roles將被刪除。 //而fetch=FetchType.EAGER表示急加載,即指一旦主表進(jìn)行了相應(yīng)操作,則從表也將立即進(jìn)行相應(yīng)的級(jí)聯(lián)操作。 //例如,一旦讀取了user表的某一個(gè)實(shí)例,則user會(huì)立即加載Roles;而fetch=FetchType.LAZY為懶加載,當(dāng)需要使用到getRolelist()方法時(shí),才會(huì)讀取相關(guān)聯(lián)的級(jí)聯(lián)表數(shù)據(jù) @OrderBy(value= "id ASC")//獲取的角色信息根據(jù)角色表的id進(jìn)行升序排序 private Set<Roles> rolelist; public Set<Roles> getRolelist() { return rolelist; } public void setRolelist(Set<Roles> rolelist) { this.rolelist = rolelist; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } }
被維護(hù)的級(jí)聯(lián)表,多個(gè)Roles角色可能對(duì)應(yīng)1個(gè)用戶
實(shí)體類Roles,代碼如下:
package ywcai.ls.entity; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name="roles") public class Roles { @Id @GeneratedValue(strategy= GenerationType.AUTO) @Column(name="id") private Long id; @Column(name="username") private String username; @Column(name="rolename") private String rolename; @ManyToOne(cascade={CascadeType.REFRESH},fetch=FetchType.LAZY) @JoinColumn(name="userid")//加入一列作為外鍵 private User user; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getRolename() { return rolename; } public void setRolename(String rolename) { this.rolename = rolename; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
二、存在異常的問(wèn)題
當(dāng)Roles類級(jí)聯(lián)操作屬性使用(cascade={CascadeType.REFRESH},這樣主要為達(dá)到對(duì)從表的某一個(gè)用戶的權(quán)限進(jìn)行操作,而不影響主表User。
這時(shí)候Roles的注解
@ManyToOne(cascade={CascadeType.REFRESH},fetch=FetchType.EAGER)
通過(guò)user對(duì)Roles進(jìn)行增加操作時(shí),無(wú)任何問(wèn)題。但單獨(dú)對(duì)Roles表中的一項(xiàng)進(jìn)行刪除,例如單獨(dú)刪除A用戶的管理員橘色,則無(wú)法刪除。
@Repository @Table(name="roles") @Qualifier("rolesRepository") public interface RolesRepository extends JpaRepository<Roles, Long > { @Transactional int deleteByUsernameAndRolename(String username,String rolename); }
首先通過(guò)JpaRepository約束接口刪除數(shù)據(jù),必須開啟事務(wù),否則報(bào)錯(cuò)。
而開啟事務(wù)后,該刪除代碼可以執(zhí)行,執(zhí)行返回的結(jié)果也正常返回1,但實(shí)際的數(shù)據(jù)中卻沒(méi)有反應(yīng),數(shù)據(jù)無(wú)法被刪除。
三、異常原因分析
出現(xiàn)該問(wèn)題的原因是Roles使用了CascadeType.REFRESH注解,Roles刪除了該表中的相應(yīng)數(shù)據(jù)后,會(huì)自動(dòng)試圖去刪除主表中該USER實(shí)體數(shù)據(jù)。但由于注解中僅賦予了CascadeType.REFRESH,讀取刷新數(shù)據(jù)的權(quán)限,因此刪除主表中該USER實(shí)體數(shù)據(jù)的語(yǔ)句是無(wú)法執(zhí)行的,最終造成了整個(gè)deleteByUsernameAndRolename()事務(wù)的失敗回滾,結(jié)果就是要?jiǎng)h的數(shù)據(jù)沒(méi)刪掉。
若在Roles實(shí)體類增加CascadeType.REMOVE權(quán)限,雖deleteByUsernameAndRolename()的事務(wù)可以正常執(zhí)行,但會(huì)造成主表USER用戶也被整體刪除,進(jìn)而反過(guò)來(lái)造成Roles表中所有該USER的角色也都被刪除。顯然,這和業(yè)務(wù)需求也不符合。
四、解決方案
上訴的問(wèn)題看起來(lái)已經(jīng)是一個(gè)邏輯相悖的矛盾,無(wú)法解決。實(shí)際上只需要將Roles中加載模式改為懶加載即可,User實(shí)體類的加載模式不需改變。
當(dāng)刪除roles中記錄時(shí)不會(huì)立即觸發(fā)到對(duì)User實(shí)體類數(shù)據(jù)的刪除,也就不會(huì)報(bào)錯(cuò)和造成失誤的回滾。
jpa onetomany的用法
one部分
時(shí)機(jī)項(xiàng)目中使用到的。
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.LAZY,mappedBy="dcpDataServiceManage") private List<DcpDataServiceTableFieldEntity> dataServiceTableFieldList;
注意這個(gè)mappBy 要和many部分字段對(duì)應(yīng)上
many部分
/** * 關(guān)聯(lián)的 */ @ManyToOne @JoinColumn(referencedColumnName = "gid") private DcpDataServiceManageEntity dcpDataServiceManage;
這塊注意的是數(shù)據(jù)庫(kù)保存的是實(shí)體類的gid.。one部分mappBy就是這個(gè)字段名。
注意
這塊就可以省去中間的一張關(guān)聯(lián)表。由于項(xiàng)目的原因。不能采用jpa 自動(dòng)建表的功能。這里使用的是sql。 特別注意的是這個(gè)字段名在數(shù)據(jù)庫(kù)創(chuàng)建的時(shí)候要加GID的
像上面代碼塊的字段 根據(jù)表映射規(guī)則 數(shù)據(jù)庫(kù)存的字段應(yīng)該是DCP_DATA_SERVICE_MANAGE_GID 這個(gè)要注意一下
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
一場(chǎng)由Java中Integer引發(fā)的踩坑實(shí)戰(zhàn)
Java中的數(shù)據(jù)類型分為基本數(shù)據(jù)類型和復(fù)雜數(shù)據(jù)類型int是前者而integer是后者(也就是一個(gè)類),下面這篇文章主要給大家介紹了關(guān)于由Java中Integer引發(fā)的踩坑實(shí)戰(zhàn),需要的朋友可以參考下2022-11-11GateWay動(dòng)態(tài)路由與負(fù)載均衡詳細(xì)介紹
這篇文章主要介紹了GateWay動(dòng)態(tài)路由與負(fù)載均衡,GateWay支持自動(dòng)從注冊(cè)中心中獲取服務(wù)列表并訪問(wèn),即所謂的動(dòng)態(tài)路由2022-11-11springboot項(xiàng)目攔截器重定向循環(huán)問(wèn)題的解決
這篇文章主要介紹了springboot項(xiàng)目攔截器重定向循環(huán)問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09帶你了解Java數(shù)據(jù)結(jié)構(gòu)和算法之二叉樹
這篇文章主要為大家介紹了Java數(shù)據(jù)結(jié)構(gòu)和算法之二叉樹,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-01-01Java面向?qū)ο笾^承、構(gòu)造方法、重寫、重載
本章具體介紹了什么是構(gòu)造方法、繼承、重寫、重載以及創(chuàng)建方法,整篇文章用老司機(jī)和人類來(lái)舉例,圖解穿插代碼案例,需要的朋友可以參考下2023-03-03打開.properties中文顯示unicode編碼問(wèn)題以及解決
這篇文章主要介紹了打開.properties中文顯示unicode編碼問(wèn)題以及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01Springboot啟動(dòng)擴(kuò)展點(diǎn)超詳細(xì)教程小結(jié)
這篇文章主要介紹了Springboot啟動(dòng)擴(kuò)展點(diǎn)超詳細(xì)教程小結(jié),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07