简体   繁体   English

JPA Hibernate-级联删除数据库和注释

[英]JPA Hibernate - cascade delete in both database and annotation

Brief 简要

I am wondering what I should do as I have read many articles trying to understand this, including many SO questions. 我想知道应该怎么做,因为我读了许多试图理解这一点的文章,包括许多SO问题。 Nothing I have read has quite hit the nail on the head with this one. 我所读到的东西都还没有触及到这个。

I want to know what happens when a database is defined with cascade rules as well as the application since this will define whether I should take the following approach or another. 我想知道用级联规则定义数据库以及应用程序时会发生什么,因为这将定义我是否应该采用以下方法。

Example tables 示例表

create table foo(
  id int unsigned not null auto_increment,
  primary key(id)
);

create table bar(
  id int unsigned not null auto_increment,
  foo_id int unsigned not null,
  primary key(id),
  foreign key(foo_id) references foo(id) on delete cascade on update cascade
)

Example classes 示例类

@Entity
@Table(name = "foo")
public class Foo {

  private int id;
  private List<Bar> bars;

  @Id
  @GeneratedValue
  @Column(name = "id")
  public int getId() {
    return id;
  }

  @OneToMany(mappedBy = "foo", cascade = {CascadeType.ALL})
  public List<Bar> getBars() {
    return bars;
  }

  public void setId() {
    this.id = id;
  }

  public void setBars(List<Bar> bars) {
    this.bars = bars;
  }

}

@Entity
@Table(name = "bar")
public class Bar {

  private int id;
  private Foo foo;

  @Id
  @GeneratedValue
  @Column(name = "id")
  public int getId() {
    return id;
  }

  @ManyToOne
  @JoinColumn(name = "foo_id", nullable = false)
  public getFoo() {
    return foo;
  }

  public void setId(int id) {
    this.id = id;
  }

  public void setFoo(Foo foo) {
    this.foo = foo;
  }

}

Questions 问题

If I now call a delete operation (be it through EntityManagerFactory or SessionFactory ) on a Foo object, which of the following will occur? 如果我现在在Foo对象上调用删除操作(通过EntityManagerFactorySessionFactory ),将发生以下哪项?

  1. The hibernate operation will delete all records in the bar table whose foreign key is that of Foo 's foo_id and then delete the Foo record. 休眠操作将删除bar表中外键为Foofoo_id所有记录,然后删除Foo记录。

  2. The hibernate operation will delete all corresponding Bar records that have been loaded into session cache (which may or may not be all bar records that exist in the actual database) and then delete the Foo record (the database cascade rule will then delete any remaining bar records). 休眠操作将删除已加载到会话高速缓存中的所有对应的Bar记录(可能是也可能不是实际数据库中存在的所有bar记录),然后删除Foo记录(数据库级联规则将删除所有剩余的bar记录)。

  3. The hibernate operation will attempt to delete the Foo record first and if database failure then do one of the aforementioned steps. 休眠操作将首先尝试删除Foo记录,如果数据库失败,请执行上述步骤之一。

  4. Something else happens for which I have not considered, if so what? 发生了我没有考虑过的其他事情,如果是的话,该怎么办?

Considering the following dilemna assumptions, what is the best approach? 考虑以下困境假设,最佳方法是什么?

Dilemna Dilemna

If 1 is true then it would suggest: 如果1为true,则表明:

A) Define cascade rule in database only. A)仅在数据库中定义级联规则。 Be sure to remove bars from the object in the application so they are not left detached from the database (as the database will delete their records) then make the call to delete foo . 确保从应用程序中的对象中删除bars ,以免它们与数据库分离(因为数据库将删除其记录),然后调用delete foo

OR 要么

B) Define cascade rule in application only since it will manage the database integrity thoroughly. B)仅在应用程序中定义级联规则,因为它将完全管理数据库的完整性。

NOT

C) Define cascade rules in both, since each achieve the desired result making the other a waste of processing. C)在两者中都定义级联规则,因为每个规则都可以达到期望的结果,而另一个则浪费了处理。

If 2 is true then it would suggest: 如果2为true,则表明:

Define cascade rules in both database and application so that Hibernate can take care of managing its entities and the database can clean up after since the application is not guaranteed to remove all the bar records. 在数据库和应用程序中定义级联规则,以便Hibernate可以管理其实体,并且可以保证数据库可以在此之后清理,因为不能保证应用程序会删除所有bar记录。

If 3 is true then it would suggest: 如果3为true,则表明:

Define cascade rules in both database and application since Hibernate appears to support the cascade rule already being defined at the database level. 因为Hibernate似乎支持已经在数据库级别定义的级联规则,所以在数据库和应用程序中都定义了级联规则。

If 4 is true then it would suggest: 如果4为true,则表明:

This question is even more important as I have missed something fundamental! 这个问题甚至更重要,因为我错过了一些基本知识!

Edit: Add articles I have read... 编辑:添加我已阅读的文章...

Related articles 相关文章

Conflicting views for database, application or both: 数据库,应用程序或两者的视图冲突:

SO - should-i-let-jpa-or-the-database-cascade-deletions 所以-我应该让JPA或数据库级联删除

Conflicting views for database or application: 数据库或应用程序的视图冲突:

SO - cascading-deletes-updates-using-jpa-or-inside-of-database 所以-级联删除使用JPA或在数据库内部更新

This article sheds light on what JPA providers actually do (though it should be noted that they use OpenJPA provider for their proof of operations): 本文阐明了JPA提供程序的实际作用(尽管应注意,他们使用OpenJPA提供程序来进行操作证明):

jpa-tutorial 日本教程

It states that: 它指出:

The cascading of remove and persist operations applies also on those entities that have not been loaded yet. 删除和持久操作的级联也适用于那些尚未加载的实体。 It even passes through them to other entities, potentially traversing through whole object graph. 它甚至通过它们传递给其他实体,从而有可能遍历整个对象图。

It goes on to state: 它继续说明:

The cascading of refresh, merge and detach passes only through entities that are already loaded. 刷新,合并和分离的级联仅通过已加载的实体进行。

This would mean that proposed process 2 is not true. 这意味着提议的过程2是不正确的。

if you declare cascade in the database and hibernate the database will always delete first if it supports it and the hibernate calls will not really delete anything but run anyway. 如果在数据库中声明了层叠并进入休眠状态,则数据库将始终首先删除(如果它支持它),并且休眠调用实际上并不会删除任何内容,而是无论如何都会运行。 However, since you are using hibernate its main advantage is to allow easy transition to a new database which may not support database side cascade ability. 但是,由于使用的是休眠模式,因此它的主要优点是可以轻松过渡到可能不支持数据库端级联功能的新数据库。 Thus you would want to leave them in there even if your database supports cascade and the hiberate underlining jdbc statements are not currently doing anything (they may do something in the future) 因此,即使数据库支持级联并且休眠的下划线jdbc语句当前未执行任何操作(将来可能会执行某些操作),您也希望将它们保留在此处

Why would you even consider it? 你为什么还要考虑呢? It is best to stick with hibernate cascade options. 最好坚持使用休眠级联选项。 On the other side having cascade on both sides would run cascade delete two times. 在另一边具有级联的另一端将运行级联删除两次。 Once from hibernate and once managed by database. 一次从休眠状态,一次由数据库管理。

Example 189. from hibernate 5.2 docs. 例189.来自hibernate 5.2文档。 which generates below sql. 生成下面的sql。

@Entity(name = "Person")
public static class Person {
    @ManyToMany(cascade = {CascadeType.DELETE})
    private List<Address> addresses = new ArrayList<>();
    ...
}

Person person1 = entityManager.find( Person.class, personId );
entityManager.remove( person1 );
DELETE FROM Person_Address
WHERE  Person_id = 1

DELETE FROM Person
WHERE  id = 1

Now you see that hibernate deletes child entities before it deletes parent. 现在您看到休眠在删除父实体之前先删除子实体。 Database cascade will run on sql person delete but it has nothing to remove now when children were removed before. 数据库级联将在sql person delete上运行,但是当以前删除子级时,现在没有什么可删除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM