[英]JPA Hibernate - cascade delete in both database and annotation
我想知道应该怎么做,因为我读了许多试图理解这一点的文章,包括许多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;
}
}
如果我现在在Foo
对象上调用删除操作(通过EntityManagerFactory
或SessionFactory
),将发生以下哪项?
休眠操作将删除bar
表中外键为Foo
的foo_id
所有记录,然后删除Foo
记录。
休眠操作将删除已加载到会话高速缓存中的所有对应的Bar
记录(可能是也可能不是实际数据库中存在的所有bar
记录),然后删除Foo
记录(数据库级联规则将删除所有剩余的bar
记录)。
休眠操作将首先尝试删除Foo
记录,如果数据库失败,请执行上述步骤之一。
发生了我没有考虑过的其他事情,如果是的话,该怎么办?
考虑以下困境假设,最佳方法是什么?
如果1为true,则表明:
A)仅在数据库中定义级联规则。 确保从应用程序中的对象中删除bars
,以免它们与数据库分离(因为数据库将删除其记录),然后调用delete foo
。
要么
B)仅在应用程序中定义级联规则,因为它将完全管理数据库的完整性。
不
C)在两者中都定义级联规则,因为每个规则都可以达到期望的结果,而另一个则浪费了处理。
如果2为true,则表明:
在数据库和应用程序中定义级联规则,以便Hibernate可以管理其实体,并且可以保证数据库可以在此之后清理,因为不能保证应用程序会删除所有bar
记录。
如果3为true,则表明:
因为Hibernate似乎支持已经在数据库级别定义的级联规则,所以在数据库和应用程序中都定义了级联规则。
如果4为true,则表明:
这个问题甚至更重要,因为我错过了一些基本知识!
编辑:添加我已阅读的文章...
数据库,应用程序或两者的视图冲突:
数据库或应用程序的视图冲突:
本文阐明了JPA提供程序的实际作用(尽管应注意,他们使用OpenJPA提供程序来进行操作证明):
它指出:
删除和持久操作的级联也适用于那些尚未加载的实体。 它甚至通过它们传递给其他实体,从而有可能遍历整个对象图。
它继续说明:
刷新,合并和分离的级联仅通过已加载的实体进行。
这意味着提议的过程2是不正确的。
如果在数据库中声明了层叠并进入休眠状态,则数据库将始终首先删除(如果它支持它),并且休眠调用实际上并不会删除任何内容,而是无论如何都会运行。 但是,由于使用的是休眠模式,因此它的主要优点是可以轻松过渡到可能不支持数据库端级联功能的新数据库。 因此,即使数据库支持级联并且休眠的下划线jdbc语句当前未执行任何操作(将来可能会执行某些操作),您也希望将它们保留在此处
你为什么还要考虑呢? 最好坚持使用休眠级联选项。 在另一边具有级联的另一端将运行级联删除两次。 一次从休眠状态,一次由数据库管理。
例189.来自hibernate 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上运行,但是当以前删除子级时,现在没有什么可删除。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.