有什么区别
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
和
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
这个例子来自Java EE Tutorial,但我仍然不明白细节。
从here:-
级联删除 用 CascadeType.REMOVE(或 CascadeType.ALL,包括 REMOVE)标记引用字段表示删除操作应自动级联到该字段引用的实体对象(集合字段可以引用多个实体对象): @Entity class Employee { : @OneToOne(cascade=CascadeType.REMOVE) 私有地址地址; : } Orphan Removal JPA 2 支持额外且更积极的移除级联模式,可以使用 @OneToOne 和 @OneToMany 注释的 orphanRemoval 元素指定:@Entity class Employee { : @OneToOne(orphanRemoval=true) private Address address; : } 区别:- 两种设置的区别在于对断开关系的响应。例如,当将地址字段设置为空或另一个地址对象时。如果指定了 orphanRemoval=true,则断开连接的 Address 实例将被自动删除。这对于清理在没有来自所有者对象(例如 Employee)的情况下不应该存在的依赖对象(例如地址)很有用。如果仅指定了 cascade=CascadeType.REMOVE,则不会采取自动操作,因为断开关系不是删除操作。
了解 CascadeType.REMOVE
和 orphanRemoval=true
之间区别的简单方法。
对于孤立删除:如果您调用 setOrders(null)
,相关的 Order
实体将在 db 中自动删除。
对于删除级联:如果您调用 setOrders(null)
,则相关的 Order
实体将不在 db 中自动删除。
假设我们有一个子实体和一个父实体。一个父母可以有几个孩子。
@Entity
class parent {
//id and other fields
@OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
Set<Person> myChildern;
}
orphanRemoval 是一个 ORM 概念,它告诉孩子是否是孤儿。它也应该从数据库中删除。
当无法从其父级访问子级时,该子级将成为孤儿。例如,如果我们删除 Person 对象集(将其设置为空集)或将其替换为新集,则父级无法再访问旧集中的子级,并且子级将成为孤儿,因此子级注定要成为也在数据库中删除。
CascadeType.REMOVE 是一个数据库级别的概念,它告诉如果父表被删除,它在子表中的所有相关记录都应该被删除。
CascadeType.REMOVE
CascadeType.REMOVE
策略,您可以显式配置:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();
或从 CascadeType.ALL
策略隐式继承:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();
允许您将 remove
操作从父实体传播到其子实体。
因此,如果我们获取父 Post
实体及其 comments
集合,并删除 post
实体:
Post post = entityManager.createQuery("""
select p
from Post p
join fetch p.comments
where p.id = :id
""", Post.class)
.setParameter("id", postId)
.getSingleResult();
entityManager.remove(post);
Hibernate 将执行三个删除语句:
DELETE FROM post_comment
WHERE id = 2
DELETE FROM post_comment
WHERE id = 3
DELETE FROM post
WHERE id = 1
PostComment
子实体因 CascadeType.REMOVE
策略而被删除,就好像我们也删除了子实体一样。
孤儿移除策略
孤儿移除策略,需要通过 orphanRemoval
属性设置:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
允许您在从集合中删除子实体时删除子表行。
因此,如果我们加载 Post
实体及其 comments
集合并从 comments
集合中删除第一个 PostComment
:
Post post = entityManager.createQuery("""
select p
from Post p
join fetch p.comments c
where p.id = :id
order by p.id, c.id
""", Post.class)
.setParameter("id", postId)
.getSingleResult();
post.remove(post.getComments().get(0));
Hibernate 将为关联的 post_comment
表行执行 DELETE 语句:
DELETE FROM post_comment
WHERE id = 2
实际上,区别在于您是尝试更新数据(PATCH)还是完全替换数据(PUT)
假设您删除了 customer
,而不是使用 cascade=REMOVE
也会删除看似有意和有用的客户订单。
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
现在假设您使用 orphanRemoval="true"
更新了 customer
,它将删除所有以前的订单并用提供的订单替换它们。 (PUT
根据 REST API
)
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
如果没有 orphanRemoval
,旧订单将被保留。 (PATCH
在 REST API
方面)
不定期副业成功案例分享