SpringJPA 一對多與多對多
目錄
前言:剛學習,以後會逐步完善.
為什麼要配置實體關係對映?把冗餘的操作交給底層框架處理
第一章 一對多
1.1 簡單的例子
1.1.1 例子概述
一個使用者對應多個收藏
即一個user對應多個collection
User表: User作為一的一方所以應該是OneToMany.
1.1.2 例子詳解
cascade.all表示擁有所有的級聯操作,無論刪除還是重新整理遊離等等,具體會在下面說到.
mappedBy聲明於關係的被維護方,mappedBy在User類中聲明瞭,User就是關係的被維護方.宣告的值為關係的維護方的關係物件屬性名,那維護方就是Collection了,維護方中有一個關聯的物件的屬性名userzz,所以這裡的mappedBy的值就為userzz.
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
@Column
String username;
@Column
String password;
@Column
String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "userzz")
List<Collection> collectionList;
//省略get,set...
}
Collection表:
@JoinColumn註解中的name值表示User表將要在Collection表中生成的外來鍵,其實就是User表中的id,這裡我為了突出效果,起了一個比較搞怪的名字
@Entity
public class Collection {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
@Column
String name;
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="userIdQiShiJiuShiUserDeWaiJian")
private User userzz;
//省略get,set...
}
我這裡採用了資料庫表的自動生成,生成的資料庫:
按上面的規則生成的user表
生成的collection表
在collection表中生成了索引與外來鍵
1.2 cascade刪除策略
參考部落格:https://www.jianshu.com/p/e8caafce5445 作者:三汪
CascadeType.PERSIST
給當前設定的實體操作另一個實體的許可權
For example:
public class Student {
@ManyToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY)
private Set<Course> courses = new HashSet<>();
//其他程式碼略。
}
可以看到,我們在上面的程式碼中給了Student對Course進行級聯儲存(cascade=CascadeType.PERSIST)的許可權。此時,若Student實體持有的Course實體在資料庫中不存在時,儲存該Student時,系統將自動在Course實體對應的資料庫中儲存這條Course資料。而如果沒有這個許可權,則無法儲存該Course資料。
CascadeType.REMOVE:
Cascade remove operation,級聯刪除操作。刪除當前實體時,與它有對映關係的實體也會跟著被刪除。
CascadeType.MERGE
Cascade merge operation,級聯更新(合併)操作。當Student中的資料改變,會相應地更新Course中的資料
CascadeType.DETACH
Cascade detach operation,級聯脫管/遊離操作。如果你要刪除一個實體,但是它有外來鍵無法刪除,你就需要這個級聯許可權了。它會撤銷所有相關的外來鍵關聯。
CascadeType.REFRESH
Cascade refresh operation,級聯重新整理操作。假設場景 有一個訂單,訂單裡面關聯了許多商品,這個訂單可以被很多人操作,那麼這個時候A對此訂單和關聯的商品進行了修改,與此同時,B也進行了相同的操作,但是B先一步比A儲存了資料,那麼當A儲存資料的時候,就需要先重新整理訂單資訊及關聯的商品資訊後,再將訂單及商品儲存
CascadeType.ALL
Cascade all operations,清晰明確,擁有以上所有級聯操作許可權。
1.3 fetch載入策略
原文:https://blog.csdn.net/u010082453/article/details/43339031
1、FetchType.LAZY:懶載入,載入一個實體時,定義懶載入的屬性不會馬上從資料庫中載入。
2、FetchType.EAGER:急載入,載入一個實體時,定義急載入的屬性會立即從資料庫中載入。
3、比方User類有兩個屬性,name跟address,就像百度知道,登入後用戶名是需要顯示出來的,此屬性用到的機率極大,要馬上到資料庫查,用急載入;
而使用者地址大多數情況下不需要顯示出來,只有在檢視使用者資料是才需要顯示,需要用了才查資料庫,用懶載入就好了。所以,並不是一登入就把使用者的所有資料都載入到物件中,於是有了這兩種載入模式。
第二章 多對多
2.1 簡單的例子
2.1.1 例子概述
實體 User:使用者。
實體 Authority:許可權。
使用者和許可權是多對多的關係。一個使用者可以有多個許可權,一個許可權也可以被很多使用者擁有。
2.1.2 具體例項
User表:
JoinTable配置的是JPA自動生成的中間表的一些屬性,name代表的是中間的表的名字.
joinColumns代表的是中間表的外來鍵,關聯到關係的維護端(User),name指的是在中間表的生成的外來鍵的名字,referencedColumnName指的是User的哪個屬性對映到中間表中當外來鍵.
inverseJoinColumns也是指定外來鍵的名字,關聯到關係的被維護端(Authority),name指的是在中間表的生成的外來鍵的名字,referencedColumnName指的是Authority的哪個屬性對映到中間表中當外來鍵.
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
@Column
String username;
@Column
String password;
@Column
String name;
/* @ManyToMany(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
如果需要載入與更新配置可以參照上面進行配置,這裡只介紹下基礎
*/
@ManyToMany
@JoinTable(name = "userAuthority",[email protected](name = "userDeId",referencedColumnName = "id"),
[email protected](name="authorityDeId",referencedColumnName = "id"))
private List<Authority> authorityListCeShiMingZi;
//省略了一些其它的屬性與get,set方法...
}
authority表:
聲明瞭mappedBy表示的這個是關係的被維護端,mappedBy的值為關係維護端的對應屬性的值
@Entity
public class Authority {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
@Column
String username;
@ManyToMany(mappedBy = "authorityListCeShiMingZi")
private List<User> userList;
}
2.1.3 生成的資料庫的結果
user表:
authority表:
中間表user_authority
索引:
外來鍵:
2.2 @ManyToMany註解說明
來自:https://www.jianshu.com/p/54108abb070f
註解可以在Collection、Set、List、Map上使用,我們可以根據業務需要選擇。
Collection類是Set和List的父類,在未確定使用Set或List時可使用;
Set集合中物件不能重複,並且是無序的;
List集合中的物件可以有重複,並且可以有排序;
Map集合是帶有key和value值的集合。
同時,我們宣告的集合需要進行初始化。
如Collection可以初始化為ArrayList或HashSet;
Set可以初始化為HashSet;
List可以初始化為ArrayList;
Map可以初始化為HashMap。
第三章 一些思考
3.1 維護端與不維護端的區別
舉例來說User表與authority表
在User表中的List<authority>中新增authority並儲存的話就能把將關係儲存
在Authority表中的List<User>中新增User並儲存就不能儲存關係
包括刪除也是一樣,若獲得User並清空List<authority>則其對應關係會被清空
但是authority不會被清空
@Test
public void test() {
System.out.println("第一個測試程式");
User user = new User();
user.setName("zhangsan");
Authority authority = new Authority();
authority.setRole("student");
user.getAuthorityListCeShiMingZi().add(authority);
//user,authority,兩者的關係,三個資料都得以儲存
userServiceImpl.save(user);
}
@Test
public void test2() {
System.out.println("第二個測試程式");
User user = new User();
user.setName("zhangsan2");
Authority authority = new Authority();
authority.setRole("student2");
authority.getUserList().add(user);
//只能儲存authority一個物件
authorityServiceImpl.save(authority);
}
//依賴authority刪除user的對應關係
@Test
public void test4() {
System.out.println("第四個測試程式");
User user = userServiceImpl.getUser(1);
System.out.println(user.getName());
user.getAuthorityListCeShiMingZi().clear();
userServiceImpl.save(user);
}
//依賴user刪除user的對應關係
@Test
public void test5() {
System.out.println("第五個測試程式");
Authority authority = authorityServiceImpl.getByRole("student");
System.out.println("size :"+authority.getUserList().size());
authority.getUserList().clear();
authorityServiceImpl.save(authority);
}
3.1.1 誰該做維護端,誰該做不維護端
私以為誰做維護端,誰不做的效果都是差不多的,看個人意願吧.
--------------------------------------------------------------------有待以後解決-----------------------------------------------------------------------------------
3.2 JPA效率是不是有點低了
這裡我想給已有的使用者新增已有的角色,一般如果手動加入的話,直接插入一條語句就行了,而JPA卻插入了三條語句.
例項:我通過JPA獲得id為1的user,通過JPA獲得student角色,我想給它們user與student建立一個關係
資料庫:
user:
authority:
已有關係:
執行程式碼:
//給已有的使用者增加已有的角色
@Test
public void test6() {
System.out.println("第六個測試程式");
User user = userServiceImpl.getUser(1);
System.out.println(user.getName());
Authority authority = authorityServiceImpl.getByRole("student");
System.out.println("------------------------");
user.getAuthorityListCeShiMingZi().add(authority);
userServiceImpl.save(user);
}
可以看到本來是一條語句的事情,JPA執行了很多語句,先刪除了id為1的user的所有關係,又插入了三條關係(二條原本的,三條新加的)
3.3 兩個類是如何通過註解@OneToMany或@ManyToMany聯絡到一起的
即為什麼配置了兩個註解,兩個類就能產生如此的關係,就能聯絡在一起進行如此的操作,這個有待之後的思索.