【发布时间】:2014-04-12 18:11:58
【问题描述】:
简介
我想知道我应该怎么做,因为我已经阅读了许多试图理解这一点的文章,包括许多 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 为真,则建议:
A) 仅在数据库中定义级联规则。请务必从应用程序的对象中删除bars,这样它们就不会与数据库分离(因为数据库将删除它们的记录),然后调用删除foo。
或
B) 仅在应用程序中定义级联规则,因为它将彻底管理数据库的完整性。
不是
C) 在两者中定义级联规则,因为每个都实现了预期的结果,而另一个则浪费了处理。
如果 2 为真,则建议:
在数据库和应用程序中定义级联规则,以便 Hibernate 可以负责管理其实体,并且数据库可以在之后清理,因为不能保证应用程序删除所有 bar 记录。
如果 3 为真,则建议:
在数据库和应用程序中定义级联规则,因为 Hibernate 似乎支持已经在数据库级别定义的级联规则。
如果 4 为真,那么它会建议:
这个问题更重要,因为我错过了一些基本的东西!
编辑:添加我读过的文章...
相关文章
数据库、应用程序或两者的视图冲突:
SO - should-i-let-jpa-or-the-database-cascade-deletions
数据库或应用程序的冲突视图:
SO - cascading-deletes-updates-using-jpa-or-inside-of-database
本文阐明了 JPA 提供者的实际工作(尽管应该注意,他们使用 OpenJPA 提供者来进行操作证明):
它指出:
删除和持久操作的级联也适用于那些 尚未加载的实体。它甚至通过它们到达 其他实体,可能会遍历整个对象图。
接着说:
刷新、合并和分离的级联只通过 已加载的实体。
这意味着提议的流程 2 不正确。
【问题讨论】:
-
我只会使用代码。
-
@djb 那将是选项 1. B) 并且可能是最安全的,因为该选项的唯一潜在不良影响是如果过程 2 为真(尽管我认为 2 的可能性最小)。但是,如果过程 1 为真,那么它表明不应该存在数据库级联规则,如果是这样,那么为什么其他相关的 SO 问题不这么说呢?他们要么暗示两者都存在级联规则,要么没有提及级联含义的这一方面
-
我所知道的是它必须以某种方式避免违反键约束。所以在实践中,它必须创建并遍历一棵树,删除父母直到最多叶的孩子。
-
是的,我认为流程 1 是正确的,并且它的执行方式正如您所建议的那样。然而,这肯定意味着级联规则应该定义为一个或另一个,而不是两个。我开始倾向于仅在数据库中定义,因为我想保持标准而不是混合,但是复杂的关系/大量的孩子在 JPA 中可能会变得昂贵
-
还有一个 Non-JPA Hibernate 注释 @OnDelete 允许您优化删除:eddii.wordpress.com/2006/11/16/…
标签: java mysql database hibernate jpa