1. 程式人生 > >SpringJPA 一對多與多對多

SpringJPA 一對多與多對多

目錄

第一章 一對多

1.1 簡單的例子

1.1.1 例子概述

1.1.2 例子詳解

1.2 cascade刪除策略

1.3 fetch載入策略

第二章 多對多

2.1 簡單的例子

2.1.1 例子概述

2.1.2 具體例項

2.1.3 生成的資料庫的結果 

2.2 @ManyToMany註解說明

第三章 一些思考

3.1 維護端與不維護端的區別

3.1.1 誰該做維護端,誰該做不維護端

 

前言:剛學習,以後會逐步完善.

為什麼要配置實體關係對映?把冗餘的操作交給底層框架處理

第一章 一對多

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聯絡到一起的

即為什麼配置了兩個註解,兩個類就能產生如此的關係,就能聯絡在一起進行如此的操作,這個有待之後的思索.