我可以在Hibernate管理的表中添加“ON DELETE CASCADE”吗?
我有一些由Hibernate管理的表,有各种外键约束。 Cascade on delete目前仅由Hibernate管理。 为了解决测试数据,我经常手动创建和删除一些行。 如果我可以将ON DELETE CASCADE添加到外键约束中,那将对我有很大帮助,但我不知道Hibernate是否因为数据库在Hibernate之前移除了东西而绊倒了。
很多人似乎都专注于DDL。 我的目的不是指示Hibernate使用SQL DELETE CASCADES创建DDL。 我只是想知道如果我在数据库中指定ON DELETE CASCADE 除了在参考注释上具有JPA的cascade = CascadeType.REMOVE
(例如@ManyToOne
之外是否有任何伤害。
您可以使用CascadeType.DELETE
,但此注释仅适用于EntityManager
的对象,而不适用于数据库。 您希望确保将ON DELETE CASCADE
添加到数据库约束中。 要进行validation,您可以配置JPA以生成ddl文件。 看一下ddl
文件,您会注意到ON DELETE CASCADE
不是约束的一部分。 将ON DELETE CASCADE
添加到ddl
文件中的实际SQL,然后从ddl更新数据库模式。 这将解决您的问题。
此链接显示如何在MySQL中使用ON DELETE CASCADE
for CONSTRAINT
。 您可以在约束上执行此操作。 您也可以在CREATE TABLE
或ALTER TABLE
语句中执行此操作。 JPA很可能在ALTER TABLE
语句中创建约束。 只需将ON DELETE CASCADE
添加到该语句即可。
请注意,某些JPA实现程序确实提供了此function的方法。
Hibernate使用@OnDelete
注释提供此function,因此如果您希望坚持使用标准JPAfunction,则首选使用此function或仅更新ddl文件。
我看到两个潜在的问题:
- 如果一个实体表示你在数据库中直接级联操作的表是版本化的,那么它将无法工作,因为当Hibernate试图自己删除记录时,版本检查会失败(Hibernate会假设并发线程已经更新或删除)相应的记录)。
- 如果有一些用例,您的业务逻辑会重新保留这些实体实例,这些实体实例在移除后已从父级转换为它们(例如,您正在删除旧的父级并将关联的子级迁移到新的父级,尽管为了更清晰,我会如果对于关联存在这样的用例,则根本不进行级联删除,但这取决于您,因为JPA规范允许),然后Hibernate将仅取消安排删除子项并仅删除父项,因此您将如果在数据库中级联删除,仍然会删除已删除的子项。
可能还有一些其他情况在某些情况下可能会出现问题,因此我建议不要这样做。
删除父记录时,可以使用本机数据库function删除子记录。
注意双向关系,并确保您只需指定级联插入和更新(更安全的一面)。
你提到测试目的。 我猜测,执行一些测试,删除数据,重播测试……
使用二级缓存或查询缓存时,如果直接从数据库中删除数据,缓存将会过时。 这可能会导致意外的测试结果。
所以是的,如果您使用二级/查询缓存,这将与Hibernate冲突,因为实体将不会从缓存中逐出。 确保在直接删除任何数据后清除所有缓存。 请参阅有关如何清除缓存的此问题。
官方的Hibernate 文档也提到了这个:
请注意,缓存不了解其他应用程序对持久性存储所做的更改。 但是,它们可以配置为定期使缓存的数据到期。
在@OneToMany
关系中使用orphanRemoval = true
子句。 然后,当主实体(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 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)
是否将删除操作应用于已从关系中删除的实体,并将删除操作级联到这些实体。
不要在此处使用cascade = CascadeType.REMOVE 文档
因为你的db可能会被破坏。 您可以使用正式订单。 删除子稳定,然后删除主表