我应该让JPA或数据库级联删除吗?

Ras*_*nke 12 sql jpa eclipselink cascading-deletes jpa-2.0

假设我们有两个实体,A和B. B与A有多对一的关系如下:

@Entity
public class A {
  @OneToMany(mappedBy="a_id")
  private List<B> children;
}

@Entity
public class B {
  private String data;
}
Run Code Online (Sandbox Code Playgroud)

现在,我想删除A对象并将删除级联到其所有子对象(B).有两种方法可以做到这一点:

1)添加cascade=CascadeType.ALL, orphanRemoval=true到OneToMany注释,让JPA在从数据库中删除A对象之前删除所有子项.

2)按原样保留类,只需让数据库级联删除即可.

使用后面的选项有什么问题吗?它会导致实体管理器保留对已删除对象的引用吗?我选择第二个选项的原因是选项一生成n + 1个SQL查询以进行删除,当对象A包含大量子节点时可能需要较长时间,而选项二只生成一个SQL查询然后继续愉快.对此有什么"最佳实践"吗?

Jam*_*mes 6

在EclipseLink中,如果使用@CascadeOnDelete注释,则可以使用两者.EclipseLink还将为您生成级联DDL.

请参阅 http://wiki.eclipse.org/EclipseLink/Examples/JPA/DeleteCascade

这样可以通过让数据库执行删除来优化删除,还可以通过删除对象来维护缓存和持久性单元.

请注意,orphanRemoval = true还将删除从集合中删除的对象,数据库级联约束将不会为您执行此操作,因此仍然需要在JPA中使用规则.还有一些数据库无法处理删除的关系,因为数据库只能在约束的反方向级联,具有外键的OneToOne或具有连接表的OneToMany不能在数据库上级联.


Luk*_*der 5

我更喜欢数据库.为什么?

  • 这样做数据库可能要快得多
  • 数据库应该是保存完整性和关系信息的主要场所.JPA只反映这些信息
  • 如果您使用其他应用程序/平台(即没有JPA)进行连接,您仍然可以级联删除记录,这有助于提高数据完整性

  • 你是对的,对不起,我没有彻底阅读你的问题.我想这取决于JPA的实现.也许,您可以在数据库和JPA注释类中指定级联删除.一个好的实现应该通过刷新它的缓存来反映这一点.但是我最后一次使用JPA(很久以前就使用过Hibernate),情况显然并非如此.解决方案是禁用所有缓存... (2认同)

Mar*_*itt 5

这个答案提出了一些非常有力的论点,即为什么应该由 JPA 来处理级联,而不是数据库。

这是相关的报价:

...如果您要在数据库上进行级联,而不是在 Hibernate 中声明它们(为了性能问题),您在某些情况下可能会出错。这是因为 Hibernate 将实体存储在其会话缓存中,因此它不会知道数据库以级联方式删除某些内容。

当你使用二级缓存时,你的情况更糟,因为这个缓存的寿命比 session 更长,而且只要旧值存储在这个缓存中,db 端的此类更改对于其他 session 将是不可见的。