欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA学习笔记:JPA映射关系

程序员文章站 2022-04-22 08:21:43
...

1. 单向多对一

映射配置:
// 多对一,懒加载
@ManyToOne(fetch = FetchType.LAZY)
// 多方的外键id
@JoinColumn(name = “xxx_id”)
注意:一方不要实例化
保存时,先保存一方,再保存多方

2. 单向一对多

映射配置:
// 一对多,默认懒加载,最好是写出来
@OneToMany(fetch = FetchType.LAZY)
// 多方的外键id
@JoinColumn(name = “xxx_id”)
集合最好是实例化出来,否则很容易空指针异常
保存时,先保存一方,再保存多方

3. 集合映射

List:有序,可重复,一般用在组合关系
Set:无序,不可重复,一般用在多对多,也有一对多
在声明集合的时候,一定要使用接口
Set products = new HashSet<>();
List products = new ArrayList<>();
因为Hibernate在创建了集合对象后是使用了它的的集合类PersistentSet/PersistentBag来接收数据的,而不是HashSet/ArrayList。如果我们使用接口声明(Set/List),那么它的集合类PersistentSet/PersistentBag也是实现了这个接口。所以它可以把这个类赋给Set/List。 但是我们使用HashSet/ArrayList,它们关系是平级的,不能进行转换,所以就会出现错误了。

4. 双向多对一、一对多

双向,其实就相当于配置两个单向

  1. 在java代码中让多方来维护关系(性能高),类似于单向多对一
  2. 在java 代码中让一方来维护关系(性能低-如下面的代码),类似于单向一对多。

4.1 映射配置

映射配置(一方):

@Entity
public class ProductDir {
	@Id
	@GeneratedValue
	private Long id;
	private String name;
	// 一对多,一方的关系参照多方Prodcut属性dir来管理
	@OneToMany( mappedBy = "dir")
	// 建议实例化
	private Set<Product2> products = new HashSet<Product2>();
}

映射配置(多方):

@Entity
public class Product {
	@Id
	@GeneratedValue
	private Long id;
	private String name;
	// 多对一,懒加载
	@ManyToOne(fetch = FetchType.LAZY) // 实现延迟加载
	// 配置外键列名
	 @JoinColumn(name = "dir_id")
	private ProductDir dir;
}

4.2 级联保存、删除、孤儿删除

只调用一次persist方法,通过保存一方,把与之相关联的多方一并保存
映射配置(一方):
在@OneToMany中配置属性cascade = CascadeType.PERSIST
级联删除配置cascade = CascadeType.REMOVE
cascade = CascadeType.ALL既支持级联保存,又支持级联删除,不过比较危险,容易误操作造成数据被删除。
孤儿删除:
在一方的@OneToMany中配置属性orphanRemoval = true,可以删除与该一方失去关系的多方,而不删除一方本身。

5. 单向多对多

多对多会额外建一张中间表来保存多对多的关系
保存数据随意先保存哪个多方都行
映射配置:

// 多对多,懒加载
@ManyToMany(fetch = FetchType.LAZY)
// 配置中间表的属性,表名,在中间表的列名,另一个多方在中间表中的列名
@JoinTable(name = "t_teacher_student", joinColumns = @JoinColumn(name = "teacher_id"), inverseJoinColumns = @JoinColumn(name = "student_id"))
private List<Student> students = new ArrayList<>();

6. 双向多对多

  1. 映射配置和单向多对多一样,在两个多方都配置就行,但是配置的中间表表名,和对应的列名必须一致。
  2. 可以配置级联保存,保存一个多方同时保存另一个多方
  3. 删除,直接常规删除就行,如
    entityManager.remove(student);
    student.getTeachers().remove(teacher);等
  4. 请勿配置级联删除或者CascadeType.ALL(危险操作),
    比如配置了学生这边级联删除,删除一个学生,会先删除中间表与该学生相关的关系,再该学生和该学生相关的老师;
    如果学生和老师都配置了级联删除,删除一个学生,会删除该学生的老师,然后删除该学生的老师的其他学生,然后删除其他学生的老师,一直循环到不能删除了为止,几乎相当于清空数据库(删库跑路)。

7. 一对一

7.1 唯一外键一对一

主一:

@Entity
@Table(name = "t_qq")
public class QQ {
	@Id
	@GeneratedValue
	private Long id;
	private String number;
	// 一对一
	@OneToOne(mappedBy="qq")
	private QQZone zone;
}

从一:

@Entity
@Table(name = "t_qqzone")
public class QQZone {
	@Id
	@GeneratedValue
	private Long id;
	private String name;
	// 一对一,外键不能为空
	@OneToOne(optional = false)
	// unique=true确保了一对一关系
	@JoinColumn(name = "qq_id", unique = true)
	private QQ qq;
}

7.2 共享主键一对一(不建议使用)

@Entity
public class QQZone {
	@Id
	@GeneratedValue(generator = "pkGenerator")
	@GenericGenerator(name = "pkGenerator", strategy = "foreign", parameters [email protected](name = "property", value = "qq"))
	private Long id;
	private String name;
	// 一对一,一个qq空间输入一个qq号码
	@OneToOne(optional = false)
	// 如果不加这个注解,添加QQZone信息时,就会自动在QQZone表中增加了一个外键qq_id
	@PrimaryKeyJoinColumn
	private QQ qq;
}