级联映射-级联持久化、更新和删除
1、什么是级联映射?
对于一对多或者多对一、多对多等关系对象时,当保存某个一对象时,与这个依赖的对象都应该自动保存或更新。就是保存瞬时状态的主对象时,同时将关联的对象也一起保存。
比如:部门和员工表,一对多关系,当保存部门数据时,和部门有关联的员工表也同时保存,之前我们都说各自调用persist()方法,都保存一遍。我们可不可以当保存部门或员工表时,把对应的员工或部门信息也同时保存?
2、级联映射类型
- cascade = CascadeType.PERSIST
保存主对象时,将关联的对象持久化到数据库中 - cascade = CascadeType.REFRESH
查询主对象的同时,重新查询关联的对象 - cascade = CascadeType.REMOVE
删除主对象的同时,删除关联的对象 - cascade = CascadeType.DETACH
主对象变为游离状态时,把关联的对象也转变为游离状态 - cascade = CascadeType.MERGE
更新主对象的同时,更新关联对象 - cascade = CascadeType.ALL
以上所有的级联关系简写
3、级联关系使用案例
3.1、类型定义
@Data
@Entity
public class Department {
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(cascade = CascadeType.PERSIST)
@JoinColumn(name = "department_id")
private List<Employee> employees;
}
@Data
@Entity
public class Employee {
@Id
@GeneratedValue
private long id;
private String name;
}
3.2、persistence.xml配置
<class>com.hongying.entity.one2many.Department</class>
<class>com.hongying.entity.one2many.Employee</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
3.3、默认配置时,保存-必须独自调用persist
@Test
public void save(){
Department d1=new Department();
d1.setName("IT开发部");
Employee gg=new Employee();
gg.setName("gg");
Employee jake=new Employee();
jake.setName("jake");
List<Employee> users=new ArrayList<>();
users.add(gg);
users.add(jake);
d1.setEmployees(users);
//保存
EntityManager entityManager = JpaUtil.getEntityManager();
entityManager.getTransaction().begin();
//当没有设置级联保存时,每个对象都必须独自调用persist()方法进行数据持久化
entityManager.persist(d1);
entityManager.persist(gg);
entityManager.persist(jake);
entityManager.getTransaction().commit();
entityManager.close();
}
3.4、只保存 entityManager.persist(d1) 时报错
有关联对象未保存,异常:
object references an unsaved transient instance - save the transient instance before flushing
entityManager.persist(d1);
//entityManager.persist(gg);
//entityManager.persist(jake);
4、级联映射使用
4.1、CascadeType.PERSIST
@Data
@Entity
public class Department {
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(cascade = CascadeType.PERSIST)
@JoinColumn(name = "department_id")
private List<Employee> employees;
}
此时只保存entityManager.persist(d1)
时,可以把关联对象同时保存:
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: update Employee set department_id=? where id=?
Hibernate: update Employee set department_id=? where id=?
4.2、CascadeType.REMOVE 级联删除
@Before
public void save(){
Department d1=new Department();
d1.setName("IT开发部");
Employee gg=new Employee();
gg.setName("gg");
Employee jake=new Employee();
jake.setName("jake");
List<Employee> users=new ArrayList<>();
users.add(gg);
users.add(jake);
d1.setEmployees(users);
//保存
EntityManager entityManager = JpaUtil.getEntityManager();
entityManager.getTransaction().begin();
//当没有设置级联保存时,每个对象都必须独自调用persist()方法进行数据持久化
entityManager.persist(d1);
// entityManager.persist(gg);
// entityManager.persist(jake);
entityManager.getTransaction().commit();
entityManager.close();
}
@Test
public void delete(){
EntityManager entityManager = JpaUtil.getEntityManager();
entityManager.getTransaction().begin();
//删除部门时查看是否会级联员工都会删除
Department department = entityManager.find(Department.class, 1L);
entityManager.remove(department);
entityManager.getTransaction().commit();
entityManager.close();
}
当未配置级联删除CascadeType.REMOVE
时,删除部门时,只会把关系和部门信息删除。员工信息并没有删除
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: update Employee set department_id=? where id=?
Hibernate: update Employee set department_id=? where id=?
Hibernate: select department0_.id as id1_0_0_, department0_.name as name2_0_0_ from Department department0_ where department0_.id=?
Hibernate: update Employee set department_id=null where department_id=?
Hibernate: delete from Department where id=?
4.2.2、配置级联删除 CascadeType.REMOVE
@Data
@Entity
public class Department {
@Id
@GeneratedValue
private long id;
private String name;
@OneToMany(cascade = {
CascadeType.PERSIST,CascadeType.REMOVE
})
@JoinColumn(name = "department_id")
private List<Employee> employees;
}
当配置级联删除CascadeType.REMOVE 时,删除部门信息时,会级联把当前部门下的员工信息一同删除。
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: update Employee set department_id=? where id=?
Hibernate: update Employee set department_id=? where id=?
Hibernate: select department0_.id as id1_0_0_, department0_.name as name2_0_0_ from Department department0_ where department0_.id=?
Hibernate: select employees0_.department_id as departme3_0_1_, employees0_.id as id1_1_1_, employees0_.id as id1_1_0_, employees0_.name as name2_1_0_ from Employee employees0_ where employees0_.department_id=?
Hibernate: update Employee set department_id=null where department_id=?
Hibernate: delete from Employee where id=?
Hibernate: delete from Employee where id=?
Hibernate: delete from Department where id=?
4.3、级联更新 CascadeType.MERGE
@Data
@Entity
public class Department {
@Id
@GeneratedValue
private long id;
private String name;
//cascade 设置级联映射关系。orphanRemoval 级联删除时要不要把关联数据一同删除?默认只删除关系数据
@OneToMany(cascade = {
CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.MERGE
},orphanRemoval = true)
// @OneToMany(cascade =CascadeType.ALL,orphanRemoval = true)
@JoinColumn(name = "department_id")
private List<Employee> employees;
}
@Before
public void save(){
Department d1=new Department();
d1.setName("IT开发部");
Employee gg=new Employee();
gg.setName("gg");
Employee jake=new Employee();
jake.setName("jake");
List<Employee> users=new ArrayList<>();
users.add(gg);
users.add(jake);
d1.setEmployees(users);
//保存
EntityManager entityManager = JpaUtil.getEntityManager();
entityManager.getTransaction().begin();
//只保存主对象即可
entityManager.persist(d1);
entityManager.getTransaction().commit();
entityManager.close();
}
@Test
public void update(){
EntityManager entityManager = JpaUtil.getEntityManager();
entityManager.getTransaction().begin();
Department department = entityManager.find(Department.class, 1L);
//1、添加新员工
Employee e1=new Employee();
e1.setName("new e1");
department.getEmployees().add(e1);
//2、修改员工信息
//update Employee set name=? where id=?
department.getEmployees().get(1).setName("update name");
//3、删除员工
//3.1、删除数据时,只会把关系删除,不会把子表-员工记录删除
//update Employee set department_id=null where department_id=? and id=?
//3.2、可设置 orphanRemoval=true,把级联数据也同时删除
//delete from Employee where id=?
department.getEmployees().remove(0);
//级联操作,即使不写merge()保存方法,在提交事务时,会级联更新
// entityManager.merge(department);
entityManager.getTransaction().commit();
entityManager.close();
}