1.单向一对多(掌握)
- 声明集合必须使用接口,建议将集合new出来
- 必须设置外键(不然会生成中间表)
- 默认懒加载(集合都是默认懒加载)
- 性能差不用,建议使用双向一对多,多对一
Product类(多方)
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue
private Long id;
private String name;
//get,set,方法省略...
}
ProductDir类(一方)
@Entity
@Table(name = "productdir")
public class ProductDir {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany//一对多,默认懒加载
@JoinColumn(name = "dir_id")//不设外键,会默认生成中间表
//必须使用接口声明集合
private List<Product> products = new ArrayList<>();
//省略get,set方法..
}
图解
2.双向一对多,多对一
- 单向一对多不行,才用双向一对多,多对一
- 一方放弃关系维护(实际也没维护能力,外键在的那方才有维护能力)
Employee类(多方)
@Entity
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue
private Long id;
private String name;
/*
* 多个员工对应一个部门
* */
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
//get和set方法省略...
}
Department类(一方)
@Entity
@Table(name = "department")
public class Department {
@Id
@GeneratedValue
private Long id;
private String name;
/*
* 一个部门对应多个员工
* */
@OneToMany(mappedBy = "department")//映射Employee中的department字段名
//@JoinColumn(name = "department_id")//一方放弃维护(也没能力维护)
private List<Employee> employees = new ArrayList<>();
//get和set方法忽略...
}

3.级联
cascade(级联)
- CascadeType.PERSIST(级联保存)
- CascadeType.MERGE(级联修改)
- CascadeType.REMOVE(级联删除)慎用,危险
- CascadeType.ALL(包含级联增删改)
- orphanRemoval = true(孤儿删除)
(1)级联删除(危险慎用)
练习1:删除一方,同时删除多方
//删除部门的时候,同时删除员工
@OneToMany(mappedBy = "department",cascade = CascadeType.REMOVE)
@Test
public void testDelete01(){
EntityManager entityManager = JPAUtil.createEntityManager();
entityManager.getTransaction().begin();
//查询一方部门
Department department = entityManager.find(Department.class, 1L);
//级联删除1 删除部门同时,删除员工
entityManager.remove(department);
entityManager.getTransaction().commit();
entityManager.close();
}
练习2:删除一个与一方解除了关系的多方(用到孤儿删除)
孤儿删除 orphanRemoval = true
//orphanRemoval = true孤儿删除,删除解除了关系的
@OneToMany(mappedBy = "department",cascade = CascadeType.REMOVE,orphanRemoval = true)
@Test
public void testDelete02(){
EntityManager entityManager = JPAUtil.createEntityManager();
entityManager.getTransaction().begin();
//查询一方部门
Department department = entityManager.find(Department.class, 1L);
//级联删除2 解除第一个员工与部门的关系,孤儿删除员工1
department.getEmployees().remove(0);
entityManager.getTransaction().commit();
entityManager.close();
}
练习3:解除所有关系,删除所有解除关系的多方(先获取一方,删除所有多方)
@OneToMany(mappedBy = "department",cascade = CascadeType.REMOVE,orphanRemoval = true)
@Test
public void testDelete03(){
EntityManager entityManager = JPAUtil.createEntityManager();
entityManager.getTransaction().begin();
//查询一方部门
Department department = entityManager.find(Department.class, 1L);
//级联删除2 解除该部门所有员工与部门的关系,孤儿删除所有解除关系的员工
department.getEmployees().clear();
entityManager.getTransaction().commit();
entityManager.close();
}
最强级联
@OneToMany(mappedBy = "department",cascade = CascadeType.ALL,orphanRemoval = true)
级联注意事项
- 级联能不用就不用,如果要用,就使用最强级联
- 组合关系时(如:超市小票) 使用最强级联
图解
4.单向多对多
User类
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
/*
* name:关连(中间)表名
* joinColumns = @JoinColumn(name = "user_id")当前类(表)对应外键的名称
* inverseJoinColumns = @JoinColumn(name = "role_id")关连类(表)对应外键的名称
* */
@ManyToMany
/*@JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))*/
private List<Role> roles = new ArrayList<>();
}
Role(角色类)
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue
private Long id;
private String name;
}
测试
@Test
public void testSave(){
//2个用户,3个角色
//准备两个用户
User u1 = new User();
u1.setName("章无忌");
User u2 = new User();
u2.setName("樟三疯");
//准备三个角色
Role r1 = new Role();
r1.setName("少林");
Role r2 = new Role();
r2.setName("武当");
Role r3 = new Role();
r3.setName("明教");
//建立关系
//章无忌既是武当又是明教
u1.getRoles().add(r2);
u1.getRoles().add(r3);
//樟三疯既是少林看,武当,又是明教
u2.getRoles().add(r1);
u2.getRoles().add(r2);
u2.getRoles().add(r3);
EntityManager entityManager = JPAUtil.createEntityManager();
entityManager.getTransaction().begin();
//保存用户
entityManager.persist(u1);
entityManager.persist(u2);
//保存角色
entityManager.persist(r1);
entityManager.persist(r2);
entityManager.persist(r3);
entityManager.getTransaction().commit();
entityManager.close();
}
5.双向多对多
User类
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue
private Long id;
private String name;
/*
* name:关连(中间)表名
* joinColumns = @JoinColumn(name = "user_id")当前类(表)对应外键的名称
* inverseJoinColumns = @JoinColumn(name = "role_id")关连类(表)对应外键的名称
* */
@ManyToMany
@JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private List<Role> roles = new ArrayList<>();
}
Role(角色类)
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany
@JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "role_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
private List<User> users = new ArrayList<>();
}
注意:双向多对多,必须保证中间表的名称,字段统一
- name:关连(中间)表名
- joinColumns = @JoinColumn(name = “user_id”)当前类(表)对应外键的名称
- inverseJoinColumns = @JoinColumn(name = “role_id”)关连类(表)对应外键的名称
@JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "role_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
6.多对多(级联)
练习1:级联添加 添加用户时,顺便添加角色
@ManyToMany(cascade = CascadeType.PERSIST)
练习2:删除user1(注意不是级联删除) JPA自动删除中间表user1对应内容和user1
@Test
public void testDelete(){
EntityManager entityManager = JPAUtil.createEntityManager();
entityManager.getTransaction().begin();
//中间表时JPA自己控制,添加删除都是自动的
User u1 = entityManager.find(User.class, 1L);
//直接删除,JPA自动删除中间表对应内容
entityManager.remove(u1);
entityManager.getTransaction().commit();
entityManager.close();
}
练习3:一边配置联级删除 User类配置联级删除 删除user1
User u1 = entityManager.find(User.class, 1L);
entityManager.remove(u1);
效果如下:
武当和明教都被删了
练习4:两边都配置联级删除,和user1有关的所有的信息都被删了
该例子中,所有数据都被删了
User u1 = entityManager.find(User.class, 1L);
entityManager.remove(u1);
多对多
7.一对一
唯一外键一对一(掌握) 唯一外键扩展性强,常用
共享主键一对一(了解) 关系强烈,扩展性不强