[英]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.