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

问题描述 投票:14回答:6

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


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

java sql hibernate jpa
6个回答
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文件。


2
投票

我看到两个潜在的问题:

  1. 如果一个实体表示你在数据库中直接级联操作的表是版本化的,那么它将无法工作,因为当Hibernate试图自己删除记录时,版本检查会失败(Hibernate会假设并发线程已经更新或删除)相应的记录)。
  2. 如果有一些用例,您的业务逻辑会重新保留这些实体实例,这些实体实例在移除后已从父级转换为它们(例如,您正在删除旧的父级并将关联的子级迁移到新的父级,尽管为了更清晰,我会如果对于关联存在这样的用例,则根本不进行级联删除,但是由JPA规范允许,这取决于你,然后Hibernate只会un-schedule删除子进程并仅删除父进程,所以你仍然会结束如果您在数据库中级联删除,则删除子项。

可能还有一些其他情况在某些情况下可能会出现问题,因此我建议不要这样做。


0
投票

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

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


0
投票

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

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

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

官方的Hibernate docs也提到了这个:

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


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)

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


-1
投票

不要使用cascade = CascadeType.REMOVE Documentation here

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

© www.soinside.com 2019 - 2024. All rights reserved.