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

时间:2022-03-12 10:25:53

I have some tables managed by Hibernate with various foreign key constraints. Cascade on delete is currently managed by Hibernate alone. For playing around with test data I often create and remove some rows by hand. It would help me a lot if I could add ON DELETE CASCADE to the foreign key constraints but I don't know if Hibernate trips over this because the database removes stuff before Hibernate does.

我有一些表由Hibernate管理,带有各种外键约束。级联删除目前仅由Hibernate管理。为了处理测试数据,我经常手工创建和删除一些行。如果我能将删除级联添加到外键约束中,将会对我有很大的帮助,但是我不知道Hibernate是否会因此而中断,因为数据库在Hibernate之前删除了一些东西。


A lot of people seem to concentrate on DDL. My intention is not to instruct Hibernate to create DDL with SQL DELETE CASCADES. I just want to know if it does any harm if I specify an ON DELETE CASCADE in the database in addition to having JPA's cascade = CascadeType.REMOVE on the reference annotation, e.g., @ManyToOne.

很多人似乎都专注于DDL。我的目的不是指示Hibernate用SQL删除级联创建DDL。我只是想知道,如果我在数据库中指定了一个删除级联,除了具有JPA的CASCADE = CascadeType之外,它是否还有什么害处。删除引用注释,例如,@ManyToOne。

6 个解决方案

#1


2  

You can use CascadeType.DELETE, however this annotation only applies to the objects in the EntityManager, not the database. You want to be sure that ON DELETE CASCADE is added to the database constraint. To verify, you can configure JPA to generate a ddl file. Take a look at the ddl file, you'll notice that ON DELETE CASCADE is not part of the constraint. Add ON DELETE CASCADE to actual SQL in the ddl file, then update your database schema from the ddl. This will fix your problem .

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

This link shows how to use ON DELETE CASCADE on for CONSTRAINT in MySQL. You do this on the constraint. You can also do it in a CREATE TABLE or ALTER TABLE statement. It's likely that JPA creates the constraint in an ALTER TABLE statement. Simply add ON DELETE CASCADE to that statement.

这个链接展示了如何在MySQL中对约束使用DELETE CASCADE。你在约束条件下做这个。您还可以在CREATE TABLE或ALTER TABLE语句中执行。JPA很可能在ALTER TABLE语句中创建约束。只需将删除级联添加到该语句中。

Note that some JPA implementors do provide a means for this functionality.

请注意,有些JPA实现人员确实为这个功能提供了一种方法。

Hibernate does supply this functionality using the @OnDelete annotation, thus it is preferred to use this or simply update the ddl file if you would like to stick with standard JPA functionality.

Hibernate使用@OnDelete注释提供了这个功能,因此如果您希望使用标准的JPA功能,最好使用这个或简单地更新ddl文件。

#2


2  

I see two potential issues:

我看到了两个潜在的问题:

  1. If an entity that represents the table to which you cascade operations directly in the database is versioned, then it would not work because when Hibernate tries to delete records on its own, the version check would fail (Hibernate would assume concurrent thread already updated or deleted the corresponding records).
  2. 如果表示直接在数据库中执行级联操作的表的实体被版本化,那么它将无法工作,因为当Hibernate尝试自行删除记录时,版本检查将失败(Hibernate将假设已更新或删除相应记录的并发线程)。
  3. If there are use cases in which your business logic re-persists such entity instances after removal has been cascaded to them from the parent (for example, you are deleting old parent and migrating associated children to a new one, although for better clarity I would not cascade removal at all if such a use case exists for an association, but it's up to you as it is allowed by the JPA spec), then Hibernate would just un-schedule the deletion of children and delete only the parent, so you would still end up with deleted children if you cascade deletion in the database.
  4. 如果有这样的用例中,您的业务逻辑re-persists实体实例级联删除后对他们的父母(例如,你删除旧父母和孩子有关迁移到一个新的,虽然为了更好的清楚我不会级联删除如果这样一个用例存在关联,但这完全取决于你,因为它是允许通过JPA规范),然后Hibernate只un-schedule儿童的删除和删除只有父母,因此,如果在数据库中进行级联删除,最终仍然会得到被删除的子节点。

Probably there are some other situations that could be problematic in some scenarios, so I would recommend not to do it.

可能在某些场景中还有其他一些情况可能会出现问题,所以我建议不要这样做。

#3


0  

You can use the native database functionality to delete the child records upon deletion of parent record.

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

Be aware of bi-directional relationships and to be sure, ensure you just specify insert and update in cascade (to be on safer side).

要注意双向关系,并确保您只是在cascade中指定插入和更新(以便更安全)。

#4


0  

You mention for testing purposes. I'm guessing, execute some test, delete data, replay test...

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

When using second-level caching or query cache, the cache will and up being stale if you directly remove the data from the database. This might result in unexpected test results.

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

So yes, this will conflict with Hibernate if you use second-level / query caching as the entity's will not get evicted from cache. Make sure all caches get cleared after you directly deleted any data. See this question on how to clear cache.

因此,如果您使用二级/查询缓存作为实体的不会从缓存中被逐出,这将与Hibernate冲突。确保所有缓存在您直接删除任何数据后被清除。关于如何清除缓存,请参见这个问题。

The official Hibernate docs also mention this:

官方的Hibernate文档也提到了这一点:

Be aware that caches are not aware of changes made to the persistent store by other applications. They can, however, be configured to regularly expire cached data.

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

#5


0  

Use orphanRemoval = true clause in your @OneToMany relation. Then when the main entity (ParameterGroup) gets deleted, every related record (Parameter) will get deleted first. Just delete ParameterGroup entity via entityManager. Also remember to set cascade clause as CascadeType.ALL (support all cascade operations) or CascadeType.REMOVE (support only cascade deletion).

在@OneToMany关系中使用孤儿院= true子句。然后当删除主实体(ParameterGroup)时,首先删除所有相关记录(参数)。只需通过entityManager删除参数组实体。还要记住将cascade子句设置为CascadeType。所有(支持所有级联操作)或CascadeType。删除(只支持级联删除)。

@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;

}

From documentation:

从文档:

public abstract boolean orphanRemoval (Optional)

公共抽象布尔孤儿院(可选)

Whether to apply the remove operation to entities that have been removed from the relationship and to cascade the remove operation to those entities.

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

#6


-1  

Don't use cascade = CascadeType.REMOVE Documentation here

不要使用cascade = CascadeType。删除文档在这里

Because of your db may be destroyed. You can use formal order. Delete sub stable and then remove master table

因为你的数据库可能被破坏。你可以用正式的顺序。删除子稳定,然后删除主表

#1


2  

You can use CascadeType.DELETE, however this annotation only applies to the objects in the EntityManager, not the database. You want to be sure that ON DELETE CASCADE is added to the database constraint. To verify, you can configure JPA to generate a ddl file. Take a look at the ddl file, you'll notice that ON DELETE CASCADE is not part of the constraint. Add ON DELETE CASCADE to actual SQL in the ddl file, then update your database schema from the ddl. This will fix your problem .

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

This link shows how to use ON DELETE CASCADE on for CONSTRAINT in MySQL. You do this on the constraint. You can also do it in a CREATE TABLE or ALTER TABLE statement. It's likely that JPA creates the constraint in an ALTER TABLE statement. Simply add ON DELETE CASCADE to that statement.

这个链接展示了如何在MySQL中对约束使用DELETE CASCADE。你在约束条件下做这个。您还可以在CREATE TABLE或ALTER TABLE语句中执行。JPA很可能在ALTER TABLE语句中创建约束。只需将删除级联添加到该语句中。

Note that some JPA implementors do provide a means for this functionality.

请注意,有些JPA实现人员确实为这个功能提供了一种方法。

Hibernate does supply this functionality using the @OnDelete annotation, thus it is preferred to use this or simply update the ddl file if you would like to stick with standard JPA functionality.

Hibernate使用@OnDelete注释提供了这个功能,因此如果您希望使用标准的JPA功能,最好使用这个或简单地更新ddl文件。

#2


2  

I see two potential issues:

我看到了两个潜在的问题:

  1. If an entity that represents the table to which you cascade operations directly in the database is versioned, then it would not work because when Hibernate tries to delete records on its own, the version check would fail (Hibernate would assume concurrent thread already updated or deleted the corresponding records).
  2. 如果表示直接在数据库中执行级联操作的表的实体被版本化,那么它将无法工作,因为当Hibernate尝试自行删除记录时,版本检查将失败(Hibernate将假设已更新或删除相应记录的并发线程)。
  3. If there are use cases in which your business logic re-persists such entity instances after removal has been cascaded to them from the parent (for example, you are deleting old parent and migrating associated children to a new one, although for better clarity I would not cascade removal at all if such a use case exists for an association, but it's up to you as it is allowed by the JPA spec), then Hibernate would just un-schedule the deletion of children and delete only the parent, so you would still end up with deleted children if you cascade deletion in the database.
  4. 如果有这样的用例中,您的业务逻辑re-persists实体实例级联删除后对他们的父母(例如,你删除旧父母和孩子有关迁移到一个新的,虽然为了更好的清楚我不会级联删除如果这样一个用例存在关联,但这完全取决于你,因为它是允许通过JPA规范),然后Hibernate只un-schedule儿童的删除和删除只有父母,因此,如果在数据库中进行级联删除,最终仍然会得到被删除的子节点。

Probably there are some other situations that could be problematic in some scenarios, so I would recommend not to do it.

可能在某些场景中还有其他一些情况可能会出现问题,所以我建议不要这样做。

#3


0  

You can use the native database functionality to delete the child records upon deletion of parent record.

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

Be aware of bi-directional relationships and to be sure, ensure you just specify insert and update in cascade (to be on safer side).

要注意双向关系,并确保您只是在cascade中指定插入和更新(以便更安全)。

#4


0  

You mention for testing purposes. I'm guessing, execute some test, delete data, replay test...

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

When using second-level caching or query cache, the cache will and up being stale if you directly remove the data from the database. This might result in unexpected test results.

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

So yes, this will conflict with Hibernate if you use second-level / query caching as the entity's will not get evicted from cache. Make sure all caches get cleared after you directly deleted any data. See this question on how to clear cache.

因此,如果您使用二级/查询缓存作为实体的不会从缓存中被逐出,这将与Hibernate冲突。确保所有缓存在您直接删除任何数据后被清除。关于如何清除缓存,请参见这个问题。

The official Hibernate docs also mention this:

官方的Hibernate文档也提到了这一点:

Be aware that caches are not aware of changes made to the persistent store by other applications. They can, however, be configured to regularly expire cached data.

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

#5


0  

Use orphanRemoval = true clause in your @OneToMany relation. Then when the main entity (ParameterGroup) gets deleted, every related record (Parameter) will get deleted first. Just delete ParameterGroup entity via entityManager. Also remember to set cascade clause as CascadeType.ALL (support all cascade operations) or CascadeType.REMOVE (support only cascade deletion).

在@OneToMany关系中使用孤儿院= true子句。然后当删除主实体(ParameterGroup)时,首先删除所有相关记录(参数)。只需通过entityManager删除参数组实体。还要记住将cascade子句设置为CascadeType。所有(支持所有级联操作)或CascadeType。删除(只支持级联删除)。

@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;

}

From documentation:

从文档:

public abstract boolean orphanRemoval (Optional)

公共抽象布尔孤儿院(可选)

Whether to apply the remove operation to entities that have been removed from the relationship and to cascade the remove operation to those entities.

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

#6


-1  

Don't use cascade = CascadeType.REMOVE Documentation here

不要使用cascade = CascadeType。删除文档在这里

Because of your db may be destroyed. You can use formal order. Delete sub stable and then remove master table

因为你的数据库可能被破坏。你可以用正式的顺序。删除子稳定,然后删除主表