我可以在Hibernate管理的表中添加“ON DELETE CASCADE”吗?

时间:2013-10-30 15:25:38

标签: java sql hibernate jpa

我有一些由Hibernate管理的表,有各种外键约束。 Cascade on delete目前仅由Hibernate管理。为了解决测试数据,我经常手动创建和删除一些行。如果我可以将ON DELETE CASCADE添加到外键约束中,那将对我有很大的帮助,但我不知道Hibernate是否因为数据库在Hibernate之前删除了东西而绊倒了。


很多人似乎都专注于DDL。我的意图是来指示Hibernate使用SQL DELETE CASCADES创建DDL。我只是想知道如果我在数据库中添加>指定ON DELETE CASCADE以使JPA cascade = CascadeType.REMOVE在参考注释上,例如@ManyToOne,是否会造成任何伤害。

7 个答案:

答案 0 :(得分:2)

您可以使用CascadeType.DELETE,但此注释仅适用于EntityManager中的对象,而不适用于数据库。您希望确保将ON DELETE CASCADE添加到数据库约束中。要进行验证,您可以配置JPA以生成ddl文件。看一下ddl文件,您会注意到ON DELETE CASCADE不是约束的一部分。将ON DELETE CASCADE添加到ddl文件中的实际SQL,然后从ddl更新数据库模式。这将解决您的问题。

link显示了如何在MySQL中ON DELETE CASCADE使用CONSTRAINT。您可以在约束上执行此操作。您也可以在CREATE TABLEALTER TABLE语句中执行此操作。 JPA可能会在ALTER TABLE语句中创建约束。只需将ON DELETE CASCADE添加到该语句中即可。

请注意,某些JPA实现者确实提供了此功能的方法。

Hibernate使用@OnDelete注释提供此功能,因此如果您希望坚持使用标准JPA功能,则首选使用此功能或仅更新ddl文件。

答案 1 :(得分:2)

我发现了两个潜在的问题:

  1. 如果一个实体表示你在数据库中直接级联操作的表是版本化的,那么它就行不通,因为当Hibernate试图自己删除记录时,版本检查会失败(Hibernate会假设已经并发了线程)更新或删除了相应的记录)。
  2. 如果有一些用例,其中您的业务逻辑重新保留了这些实体实例,这些实体实例在移除后已从父级转换为它们(例如,您正在删除旧的父级并将关联的子级迁移到新的父级,尽管为了更好清晰度如果对于关联存在这样的用例,我根本不会级联删除,但是由于JPA规范允许的话,它会由你决定,然后Hibernate只会un-schedule删除子进程并且只删除父项,因此如果在数据库中级联删除,最终仍会删除已删除的子项。
  3. 在某些情况下可能存在其他一些可能存在问题的情况,因此我建议来执行此操作。

答案 2 :(得分:0)

您可以使用本机数据库功能在删除父记录时删除子记录。

请注意双向关系,并确保您只需指定级联插入和更新(更安全的一面)。

答案 3 :(得分:0)

您提及测试目的。我猜测,执行一些测试,删除数据,重播测试...

使用二级缓存或查询缓存时,如果直接从数据库中删除数据,缓存将会过时。 这可能会导致意外的测试结果。

所以是的,如果您使用二级/查询缓存,这将与Hibernate冲突,因为实体不会从缓存中逐出。确保在直接删除任何数据后清除所有缓存。 See this question on how to clear cache.

官方Hibernate docs也提到了这个:

  

请注意,缓存不了解其他应用程序对持久性存储所做的更改。但是,它们可以配置为定期使缓存的数据到期。

答案 4 :(得分:0)

orphanRemoval = true关系中使用@OneToMany子句。然后,当主实体(ParameterGroup)被删除时,每个相关记录(参数)将首先被删除。只需通过entityManager删除ParameterGroup实体。还记得将cascade子句设置为CascadeType.ALL(支持所有级联操作)或CascadeType.REMOVE(仅支持级联删除)。

@Entity
@Table(name = "PARAMETER_GROUP")
public class ParameterGroup {

    @Id
    private Long id;

    @OneToMany(mappedBy = "parameterGroup", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Parameter> parameters = new LinkedList<>();

}

@Entity
@Table(name = "PARAMETER")
public class Parameter {

    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
    @JoinColumn(name = "PARAMETER_GROUP_ID")
    private ParameterGroup parameterGroup;

}

来自文档:

public abstract boolean orphanRemoval (Optional)

  

是否将删除操作应用于已经存在的实体   从关系中删除并将删除操作级联到   那些实体。

答案 5 :(得分:0)

只要您没有启用ON DELETE CASCADECascadeType.REMOVE来防止实体移除事件的传播,就可以安全地使用orphanRemoval

在您的关系上拥有@OnDelete(action = OnDeleteAction.CASCADE)将迫使Hibernate为相关外键生成ON DELETE CASCADE。但是,您的Dialect必须通过在true方法中返回supportsCascadeDelete来表明支持这种关系。

Dialect.supportsCascadeDelete()

OnDelete

答案 6 :(得分:-1)

请勿使用cascade = CascadeType.REMOVE Documentation here

因为你的db可能会被破坏。您可以使用正式订单。删除子稳定   然后删除主表