13

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

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

@Entity
public class B {
  private String data;
}

现在,我想删除该A对象并将删除级联到它的所有 children B。有两种方法可以做到这一点:

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

  2. 让类保持原样,让数据库级联删除。

使用后一个选项有什么问题吗?它会导致实体管理器保留对已删除对象的引用吗?我选择选项二而不是选项一的原因是选项一生成 n+1 个 SQL 查询以进行删除,当对象 A 包含很多子项时,这可能需要很长时间,而选项二仅生成一个 SQL 查询然后继续高兴地。有没有关于这个的“最佳实践”?

4

3 回答 3

9

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

  • 数据库这样做可能要快得多
  • 数据库应该是保存完整性和关系信息的主要场所。JPA 只是反映该信息
  • 如果您正在连接不同的应用程序/平台(即没有 JPA),您仍然可以级联删除您的记录,这有助于提高数据完整性
于 2011-04-26T09:02:24.540 回答
7

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

见, http://wiki.eclipse.org/EclipseLink/Examples/JPA/DeleteCascade

这通过让数据库来优化删除,但也通过删除对象来维护缓存和持久性单元。

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

于 2011-04-26T13:26:33.100 回答
5

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

这是相关的报价:

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

当你使用二级缓存时,你的情况会更糟,因为这个缓存的寿命比 session 长,而且只要旧值存储在这个缓存中,db-side 上的这种变化对其他 session 是不可见的。

于 2012-08-30T01:44:55.463 回答