从DB中删除cascade和orphan有什么区别?

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)标记引用字段表示删除操作应自动级联到该字段引用的实体对象(多个实体对象可以由集合字段引用):

@Entity
class Employee {
     :
    @OneToOne(cascade=CascadeType.REMOVE)
    private Address address;
     :
}
Run Code Online (Sandbox Code Playgroud)

孤儿去除

JPA 2支持额外且更积极的删除级联模式,可以使用@OneToOne和@OneToMany注释的orphanRemoval元素指定:

@Entity
class Employee {
     :
    @OneToOne(orphanRemoval=true)
    private Address address;
     :
}
Run Code Online (Sandbox Code Playgroud)

区别:-

两个设置之间的区别在于断开关系的响应.例如,将地址字段设置为null或另一个Address对象时.

  • 如果指定了orphanRemoval = true,则会自动删除已断开连接的Address实例.这对于清理在没有所有者对象(例如Employee)的引用时不应存在的依赖对象(例如Address)非常有用.
  • 如果仅指定了cascade = CascadeType.REMOVE,则不会执行自动操作,因为断开关系不是删除
    操作.


stu*_*udy 79

一个简单的方法来理解之间的差异CascadeType.REMOVEorphanRemoval=true.

对于孤儿删除:如果您调用setOrders(null),相关Order实体将自动在db中删除.

对于删除级联:如果调用setOrders(null),Order不会自动在db中删除相关实体.

  • 删除===删除 (2认同)

Vla*_*cea 7

级联类型.REMOVE

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集合并PostCommentcomments集合中删除第一个:

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)


Mr.*_*r.Q 6

假设我们有一个子实体和一个父实体。父母可以有几个孩子。

@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是数据库级别的概念,它告知是否删除了父级,应该删除子表中所有与其相关的记录。


gar*_*may 5

实际上,区别在于您是尝试更新数据(PATCH)还是完全替换数据(PUT)

假设您删除了customer比使用cascade=REMOVE还将删除那些看似有意且有用的客户订单。

@OneToMany(cascade=REMOVE, mappedBy="customer")
public List<Order> getOrders() { ... }
Run Code Online (Sandbox Code Playgroud)

现在假设您更新 a customerorphanRemoval="true"它将删除所有以前的订单并将其替换为提供的订单。(PUT按照REST API

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

如果没有orphanRemoval旧订单,将被保留。(PATCH按照REST API