目录
前言:刚学习,以后会逐步完善.
为什么要配置实体关系映射?把冗余的操作交给底层框架处理
第一章 一对多
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联系到一起的
即为什么配置了两个注解,两个类就能产生如此的关系,就能联系在一起进行如此的操作,这个有待之后的思索.