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

xcitsw88  于 2023-06-23  发布在  其他
关注(0)|答案(8)|浏览(152)

我有一些由Hibernate管理的表,带有各种外键约束。Cascade on delete目前由Hibernate单独管理。为了处理测试数据,我经常手工创建和删除一些行。如果我能在外键约束中添加ON DELETE CASCADE,这将对我有很大的帮助,但我不知道Hibernate是否会因为数据库在Hibernate之前删除内容而跳过这一点。
很多人似乎都把注意力集中在DDL上。我的意图是不是指示Hibernate使用SQL DELETE CASCADES创建DDL。我只是想知道如果我在数据库中指定一个ON DELETE CASCADE**,除了**在引用注解上有JPA的cascade = CascadeType.REMOVE,例如@ManyToOne,是否会有任何伤害。

avwztpqn

avwztpqn1#

您可以使用CascadeType.DELETE,但此注解仅适用于EntityManager中的对象,而不适用于数据库。您希望确保ON DELETE CASCADE已添加到数据库约束中。要进行验证,可以配置JPA以生成ddl文件。看一下ddl文件,您会注意到ON DELETE CASCADE不是约束的一部分。将ON DELETE CASCADE添加到ddl文件中的实际SQL中,然后从ddl更新数据库模式。这将解决您的问题。
这个link展示了如何在MySQL中为CONSTRAINT使用ON DELETE CASCADE。在约束上执行此操作。您也可以在CREATE TABLEALTER TABLE语句中执行此操作。JPA很可能在ALTER TABLE语句中创建约束。只需将ON DELETE CASCADE添加到该语句即可。
请注意,一些JPA实现器确实提供了一种实现此功能的方法。
Hibernate确实使用@OnDelete注解提供了这个功能,因此,如果您想坚持使用标准JPA功能,最好使用这个或简单地更新ddl文件。

t5fffqht

t5fffqht2#

只要没有启用CascadeType.REMOVEorphanRemoval来防止实体删除事件的传播,就可以安全地使用ON DELETE CASCADE
在你的关系上设置@OnDelete(action = OnDeleteAction.CASCADE)将强制Hibernate为相关外键生成ON DELETE CASCADE。然而,您的Dialect必须通过在supportsCascadeDelete方法中返回true来指示支持这种关系。
Dialect.supportsCascadeDelete()
OnDelete

ercv8c1e

ercv8c1e3#

我看到两个潜在的问题:
1.如果一个实体代表了你直接在数据库中级联操作的表,那么它将不起作用,因为当Hibernate试图自己删除记录时,版本检查将失败(Hibernate将假设并发线程已经更新或删除了相应的记录)。
1.如果在某些用例中,业务逻辑会在从父实体中级联移除这些实体示例之后重新持久化这些示例(例如,您正在删除旧的父节点并将关联的子节点迁移到新节点,尽管为了更清楚起见,如果关联存在这样的用例,我根本不会级联删除,但这取决于您,因为这是JPA规范所允许的),那么Hibernate将只是un-schedule删除子节点,而只删除父节点,所以如果在数据库中级联删除,最终还是会有被删除的子节点。
可能还有其他一些情况,在某些情况下可能会有问题,所以我建议不要这样做。

izkcnapc

izkcnapc4#

您可以使用本机数据库功能在删除父记录时删除子记录。
要注意双向关系,确保只指定级联插入和更新(为了更安全)。

bogh5gae

bogh5gae5#

你提到是为了测试目的。我猜,执行一些测试,删除数据,重播测试…
当使用二级缓存或查询缓存时,如果直接从数据库中删除数据该高速缓存将变得陈旧。这可能会导致意外的测试结果。
所以是的,如果你使用二级/查询缓存,这将与Hibernate冲突,因为实体的缓存不会被驱逐。确保在您直接删除任何数据后清除所有缓存。See this question on how to clear cache.
Hibernate的官方文档也提到了这一点:
请注意,缓存不知道其他应用程序对持久存储所做的更改。但是,它们可以被配置为定期使缓存的数据过期。

ercv8c1e

ercv8c1e6#

从我的实验来看,由于我已经为此挣扎了几个小时,在@JoinColumn中使用updatable = false将阻止Hibernate这样做。

update theTable set theReference = null where theIdentifier = ?

例如(在Kotlin中):

@Entity
@Table(name = "course")
class Course(
    @Column(name = "title")
    var title: String? = null,
    @OneToMany(cascade = [CascadeType.PERSIST])
    @JoinColumn(name = "course_id", updatable = false)
    val reviews: MutableList<Review> = mutableListOf()
) {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    var id: Int? = null

}
6ioyuze2

6ioyuze27#

几天前我在这里寻找关于删除父行时删除子行的解决方案(Casacading Deletes),我似乎已经解决了目前正在进行的项目。我使用Casade.ALL来处理我的双向多对一关系。解决方案:

// Parent Entity.
@Entity
public class Parent implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")
    private List<RequisitionDetail> children = new LinkedList<>();
    ...
    // Getters & Setters.
    ...
}

// Child Entity.
@Entity
public class Child implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "parent_id")
    private Parent parent;
    ...
    // Getters & Setters.
    ...
}

// Save your entities as below.
public void requisitionInsert() {
    try {
        Parent parent = new Parent();
        Child child = new Child();
        List<Child> children = new LinkedList<>();
        ...
        // Add parent to child
        child.setParent(parent);
        // Add child to list
        children.add(child);
        // Add children list to parent 
        parent.setChilds(children);
        // Save parent entity
        ParentDao.saveParent(parent);
    } catch (Exception e) {
        throw new RuntimeException();
    }
}

我的级联删除一开始就失败了,因为我的父行没有子行,这样做解决了我的错误,级联删除也工作得很好。

h4cxqtbf

h4cxqtbf8#

不要使用cascade = CascadeType。删除Documentation here
因为你的数据库可能会被摧毁。你可以使用正式命令。删除子稳定表,然后删除主表

相关问题