JPA 级联 Cascade 详解

由于 重复性的操作十分烦琐,尤其是在处理多个彼此关联对象情况下,此时我们可以使用级联(Cascade)操作。级联 在关联映射中是个重要的概念,指当主动方对象执行操作时,被关联对象(被动方)是否同步执行同一操作。

在实际的项目中,经常可以使用到级联的操作。本周也在级联上遇到了问题。

级联类型

jpa的级联类型(Cascade Types)包括:

  • ALL
  • PERSIST
  • MERGE
  • REMOVE
  • REFRESH
  • DETACH

ALL类型包括所有的jpa级联类型和Hibernate的级联类型。具体的使用方法,就是在实体的关联注解上使用级联类型:

@Entity  
public class Student {  
    @Id  
    @GeneratedValue(strategy = GenerationType.IDENTITY)  
    Long id;  
  
    String name; 
    
    @OneToMany(cascade = CascadeType.ALL)
    List<Course> courseList = new ArrayList<>();  
    .......
}
  
@Entity  
public class Course {  
    @Id  
   @GeneratedValue(strategy = GenerationType.IDENTITY)  
    Long id;
    
    String name;  
    .....
}

PERSIST

PERSIST操作会将对象持久化,当使用CascadeType.PERSIST时,代表持久化父对象时,子对象也相应的持久化,也就是级联保存。

Student student = new Student("s1");  
student.setCourseList(Arrays.asList(new Course("c1")));  
studentRepository.save(student);

对应的sql语句为:

insert into student (name) values (?)
insert into course (name) values (?)
insert into student_course_list (student_id, course_list_id) values (?, ?)

MERGE

MERGE操作会将具有相同标识符的对象进行更新,当时用CascadeType.MERGE时,代表当父对象更新里的子对象更新时,更新操作会传递到子对象。

➊
Student student = new Student("s1");  
student.setCourseList(Arrays.asList(new Course("c1")));  
studentRepository.save(student);  

➋
student.setName("s2");  
student.getCourseList().get(0).setName("c2");  
studentRepository.save(student);

对应➋处的sql语句为:

select student0_.id as id1_1_1_, student0_.name as name2_1_1_, courselist1_.student_id as student_1_2_3_, course2_.id as course_l2_2_3_, course2_.id as id1_0_0_, course2_.name as name2_0_0_ from student student0_ left outer join student_course_list courselist1_ on student0_.id=courselist1_.student_id left outer join course course2_ on courselist1_.course_list_id=course2_.id where student0_.id=1
update course set name=c2 where id=1
update student set name=s2 where id=1

具体流程为:

  • 从学生表中查找学生并连接课程表
  • 更新课程中改变的属性,更新学生中改变的属性

REMOVE

REMOVE操作会删除数据库的实体,使用CascadeType.REMOVE时,会级联删除所有子对象。

➊
Student student = new Student("s1");  
student.setCourseList(Arrays.asList(new Course("c1"), new Course("c2")));  
studentRepository.save(student);  
  
 ➋
studentRepository.delete(student);

➋处对应的sql语句为:

delete from student_course_list where student_id=1
delete from course where id=1
delete from course where id=2
delete from student where id=1

REFRESH

REFRESH操作代表重新从数据库中获取实体信息,使用了CascadeType.REFRESH后,会级联的获取子对象在数据库的信息。

Student student = new Student("s1");  
student.setCourseList(Arrays.asList(new Course("c1"), new Course("c2"))); 
entityManager.refresh(student); 
studentRepository.save(student);  

Cascade refresh operation,级联刷新操作。
假设场景 有一个订单,订单里面关联了许多商品,这个订单可以被很多人操作,那么这个时候A对此订单和关联的商品进行了修改,与此同时,B也进行了相同的操作,但是B先一步比A保存了数据,那么当A保存数据的时候,就需要先刷新订单信息及关联的商品信息后,再将订单及商品保存。


 

DETACH

DETACH操作表示从持久化的上下文移除对象,当使用了CascadeType.DETACH后,子对象也会从持久化的上下文中移除。

Student student = new Student("s1");  
Course course = new Course("c1");  
student.setCourseList(Arrays.asList(course));  
studentRepository.save(student);  
assertThat(entityManager.contains(student)).isTrue();  
assertThat(entityManager.contains(course)).isTrue();  
entityManager.detach(student);  
assertThat(entityManager.contains(student)).isFalse();  
assertThat(entityManager.contains(course)).isFalse();

orphanRemoval

之前的级联代表的都是从父操作到子操作的延伸,在写项目的时候,就遇到了这样的问题:学生选择了政治、英语课,然后修改学生课程为语文、数学。然而级联并不能做到当学生课程集合改变时,自动删除原先课程并创建新课程。这时候就需orphanRemoval了,官方文档给出的解释为:

When a target entity in one-to-one or one-to-many relationship is removed from the relationship, it is often desirable to cascade the remove operation to the target entity. Such target entities are considered “orphans,” and theorphanRemovalattribute can be used to specify that orphaned entities should be removed. For example, if an order has many line items and one of them is removed from the order, the removed line item is considered an orphan. IforphanRemovalis set totrue, the line item entity will be deleted when the line item is removed from the order.

TheorphanRemovalattribute in@OneToManyand@oneToOnetakes a Boolean value and is by default false.

The following example will cascade the remove operation to the orphaned customer entity when it is removed from the relationship:

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

大致就是说,当一个one-to-one或一个one-to-many的关系发生改变的时候,他会自动删除相关联的数据。

Student student = new Student("s1");  
List<Course> courses1 = new ArrayList<>();  
courses1.add(new Course("c1"));  
student.setCourseList(courses1);  
studentRepository.save(student);  
  
student.getCourseList().clear();  
student.getCourseList().add(new Course("c2"));  
studentRepository.save(student);

对应的sql语句为:

insert into course (name) values (?)
insert into student_course_list (student_id, course_list_id) values (?, ?)
delete from course where id=?

注意当子实体与其他实体还有关联时,删除操作会失败。所以orphanRemoval只适用与子实体仅与父实体有关联。

Cascade默认值

       默认值为空,表示什么都不做。

参考链接:



Overview of JPA/Hibernate Cascade Types

 

chibernate - jpa级联(Cascade)操作 - 我的专栏 - SegmentFault 思否

【简单易懂】JPA概念解析:CascadeType(各种级联操作)详解。 - 简书

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值