ran*_*m86 88 java jpa cascading-deletes
有什么区别
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
Run Code Online (Sandbox Code Playgroud)
和
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
Run Code Online (Sandbox Code Playgroud)
这个例子来自Java EE Tutorial,但我仍然不了解细节.
Rah*_*thi 136
从这里: -
级联删除
使用CascadeType.REMOVE(或CascadeType.ALL,包括REMOVE)标记引用字段表示删除操作应自动级联到该字段引用的实体对象(多个实体对象可以由集合字段引用):
Run Code Online (Sandbox Code Playgroud)@Entity class Employee { : @OneToOne(cascade=CascadeType.REMOVE) private Address address; : }
孤儿去除
JPA 2支持额外且更积极的删除级联模式,可以使用@OneToOne和@OneToMany注释的orphanRemoval元素指定:
Run Code Online (Sandbox Code Playgroud)@Entity class Employee { : @OneToOne(orphanRemoval=true) private Address address; : }
区别:-
两个设置之间的区别在于断开关系的响应.例如,将地址字段设置为null或另一个Address对象时.
- 如果指定了orphanRemoval = true,则会自动删除已断开连接的Address实例.这对于清理在没有所有者对象(例如Employee)的引用时不应存在的依赖对象(例如Address)非常有用.
- 如果仅指定了cascade = CascadeType.REMOVE,则不会执行自动操作,因为断开关系不是删除
操作.
stu*_*udy 79
一个简单的方法来理解之间的差异CascadeType.REMOVE
和orphanRemoval=true
.
对于孤儿删除:如果您调用setOrders(null)
,相关Order
实体将自动在db中删除.
对于删除级联:如果调用setOrders(null)
,Order
则不会自动在db中删除相关实体.
CascadeType.REMOVE
您可以明确配置的策略:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.REMOVE
)
private List<PostComment> comments = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)
或者从CascadeType.ALL
策略中隐式继承它:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL
)
private List<PostComment> comments = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)
允许您将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);
Run Code Online (Sandbox Code Playgroud)
Hibernate 将执行三个删除语句:
DELETE FROM post_comment
WHERE id = 2
DELETE FROM post_comment
WHERE id = 3
DELETE FROM post
WHERE id = 1
Run Code Online (Sandbox Code Playgroud)
在PostComment
子实体是因为删除的CascadeType.REMOVE
策略,表现得好像我们去掉了孩子实体。
孤儿移除策略,需要通过orphanRemoval
属性设置:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)
允许您在从集合中删除子实体时删除子表行。
因此,如果我们加载Post
实体及其comments
集合并PostComment
从comments
集合中删除第一个:
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));
Run Code Online (Sandbox Code Playgroud)
Hibernate 将为关联的post_comment
表行执行 DELETE 语句:
DELETE FROM post_comment
WHERE id = 2
Run Code Online (Sandbox Code Playgroud)
假设我们有一个子实体和一个父实体。父母可以有几个孩子。
@Entity
class parent {
//id and other fields
@OneToMany (orphanRemoval = "true",cascade = CascadeType.REMOVE)
List<Personnel> myChildernList;
}
Run Code Online (Sandbox Code Playgroud)
orphanRemoval是一个ORM概念,它告诉孩子是否是孤儿。它也应该从数据库中删除。
如果无法从其父级访问该子级,则该子级将成为孤儿。例如,如果我们删除索引i处的obj(使用myChildernList.remove(i))或将其设置为null或将其替换为新的(personnelList.set(i,newChild)),则父级将无法再访问该子级并且该孩子是孤儿,因此该孩子注定也要从数据库中删除(这令人心碎:()
CascadeType.REMOVE是数据库级别的概念,它告知是否删除了父级,应该删除子表中所有与其相关的记录。
实际上,区别在于您是尝试更新数据(PATCH)还是完全替换数据(PUT)
假设您删除了customer
比使用cascade=REMOVE
还将删除那些看似有意且有用的客户订单。
@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
Run Code Online (Sandbox Code Playgroud)
现在假设您更新 a customer
,orphanRemoval="true"
它将删除所有以前的订单并将其替换为提供的订单。(PUT
按照REST API
)
@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }
Run Code Online (Sandbox Code Playgroud)
如果没有orphanRemoval
旧订单,将被保留。(PATCH
按照REST API
)