SpringJPA 一对多与多对多

2022-06-26 08:45:46

目录

第一章 一对多

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",joinColumns=@JoinColumn(name = "userDeId",referencedColumnName = "id"),
	inverseJoinColumns=@JoinColumn(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联系到一起的

即为什么配置了两个注解,两个类就能产生如此的关系,就能联系在一起进行如此的操作,这个有待之后的思索.

  • 作者:逆袭的小学生
  • 原文链接:https://blog.csdn.net/q610376681/article/details/84979533
    更新时间:2022-06-26 08:45:46