JPA 休眠 - 数据库和注释中的级联删除

2022-09-01 10:02:22

我想知道我应该怎么做,因为我已经阅读了许多试图理解这一点的文章,包括许多SO问题。我所读到的任何东西都没有用这个来击中要害。

我想知道当使用级联规则和应用程序定义数据库时会发生什么,因为这将定义我是否应该采用以下方法或其他方法。

示例表

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
)

示例类

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

}

问题

如果我现在对对象调用删除操作(无论是通过还是 ),则会发生以下哪项操作?EntityManagerFactorySessionFactoryFoo

  1. 休眠操作将删除表中外键为 ' 的所有记录,然后删除该记录。barFoofoo_idFoo

  2. 休眠操作将删除已加载到会话缓存中的所有相应记录(可能是也可能不是实际数据库中存在的所有记录),然后删除该记录(数据库级联规则随后将删除任何剩余的记录)。BarbarFoobar

  3. 休眠操作将首先尝试删除记录,如果数据库失败,则执行上述步骤之一。Foo

  4. 其他我没有考虑过的事情,如果是这样,该怎么办?

考虑到以下困境假设,最好的方法是什么?

迪莱姆纳

如果 1 为真,则表明:

A) 仅在数据库中定义级联规则。确保从应用程序中的对象中删除,以便它们不会与数据库分离(因为数据库将删除其记录),然后调用 delete 。barsfoo

B) 仅在应用程序中定义级联规则,因为它将彻底管理数据库完整性。

C)在两者中定义级联规则,因为每个规则都实现了预期的结果,使得另一个浪费了处理。

如果 2 为真,则表明:

在数据库和应用程序中定义级联规则,以便 Hibernate 可以负责管理其实体,并且数据库可以在之后进行清理,因为不能保证应用程序删除所有记录。bar

如果 3 为真,则表明:

在数据库和应用程序中定义级联规则,因为 Hibernate 似乎支持已在数据库级别定义的级联规则。

如果 4 为真,则表明:

这个问题更重要,因为我错过了一些基本的东西!

编辑:添加我读过的文章...

相关文章

数据库视图、应用程序视图或两者冲突:

SO - should-i-let-jpa-or-the-database-cascade-deletes

数据库或应用程序的冲突视图:

SO - 级联-删除-更新-使用-jpa-或-数据库内部

本文阐明了 JPA 提供程序的实际操作(尽管应该注意的是,他们使用 OpenJPA 提供程序作为其操作证明):

jpa-tutorial

它指出:

删除和持久化操作的级联也适用于尚未加载的实体。它甚至通过它们传递到其他实体,可能会遍历整个对象图。

它继续说:

刷新、合并和分离的级联仅通过已加载的实体。

这意味着提议的过程2是不正确的。


答案 1

如果在数据库中声明级联并休眠,则数据库将始终首先删除(如果它支持它),并且休眠调用不会真正删除任何内容,但无论如何都会运行。但是,由于您正在使用休眠,因此它的主要优点是允许轻松过渡到可能不支持数据库端级联功能的新数据库。因此,即使您的数据库支持级联并且休眠下划线jdbc语句当前未执行任何操作(它们将来可能会执行某些操作),您也希望将它们保留在那里。


答案 2

你为什么会考虑它?最好坚持使用休眠级联选项。另一方面,两端都有级联将运行级联删除两次。一次来自休眠状态,一次由数据库管理。

例 189.从休眠 5.2 文档。这将生成低于 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

现在,您会看到休眠在删除父实体之前删除子实体。数据库级联将在 sql person delete 上运行,但是当之前删除子级时,它现在没有什么可删除的。


推荐