hibernate 的cascade的作用和用法
只有“關係標記”才有cascade屬性;
一個操作因級聯cascade可能觸發多個關聯操作。前一個操作叫“主控操作”,後一個操作叫“關聯操作”。
cascade屬性的可能值有
all: 所有情況下均進行關聯操作,即save-update和delete。
none: 所有情況下均不進行關聯操作。這是預設值。
save-update: 在執行save/update/saveOrUpdate時進行關聯操作。
delete: 在執行delete 時進行關聯操作。
all-delete-orphan: 當一個節點在物件圖中成為孤兒節點時,刪除該節點。比如在一個一對多的關係中,Student包含多個book,當在物件關係中刪除一個book時,此book即成為孤兒節點。
級聯(cascade)屬性的作用:
級聯指的是當主控方執行操作時,關聯物件(被動方)是否同步執行同一操作。
pojo和它的關係屬性的關係就是“主控方 -- 被動方”的關係,如果關係屬性是一個set,那麼被動方就是set中的一個一個元素,。
比如:學校(School)有三個屬性:地區(Address),校長(TheMaster)和學生(Set,元素為Student)
執行session.delete(school)時,級聯決定是否執行session.delete(Address),session.delete(theMaster),
是否對每個aStudent執行session.delete(aStudent)。
具體執行什麼“關聯操作”是根據“主控操作”來的:
“主控操作” “關聯操作”
session.saveOrUpdate --> session.saveOrUpdate (執行saveOrUpdate實際上會執行save或者update)
session.save ----> session.saveOrUpdate
session.udpate --> session.saveOrUpdate
session.delete --> session.delete
主控操作和關聯操作的先後順序是“先儲存one,再儲存many;先刪除many,再刪除one;先update主控方,再update被動方”
對於one-to-one,當其屬性constrained="false"(預設值)時,它可看作one-to-many關係;
當其屬性constrained="true"時,它可看作many-to-one關係;
對many-to-many,它可看作one-to-many。
比如:學校(School)有三個屬性:地區(Address),校長(TheMaster,其constrained="false")和學生(Set, 元素為Student)
當執行session.save(school)時,
實際的執行順序為:session.save(Address);
session.save(school);
session.save(theMaster);
for( 對每一個student ){
session.save(aStudent);
}
當執行session.delete(school)時,
實際的執行順序為:session.delete(theMaster);
for( 對每一個student ){
session.delete(aStudent);
}
session.delete(school);
session.delete(Address);
當執行session.update(school)時,
實際的執行順序為:session.update(school);
session.saveOrUpdate(Address);
session.saveOrUpdate(theMaster);
for( 對每一個student ){
session.saveOrUpdate(aStudent);
}
注意:update操作因級聯引發的關聯操作為saveOrUpdate操作,而不是update操作。
saveOrUpdate與update的區別是:前者根據操作物件是儲存了還是沒有儲存,而決定執行update還是save
extends: 實際中,刪除學校不會刪除地區,即地區的cascade一般設為false
另外,many-to-many關係很少設定cascade=true,而是設定inverse=false。這個反映了cascade和inverse的區別。見4.3
cascade的預設值為false,所以inverse屬性預設會進行“關聯更新”。
總結:級聯(cascade)就是操作一個物件時,對它的屬性(其cascade=true)也進行這個操作。
inverse和cascade的比較
這兩個屬性本身互不影響,但起的作用有些類似,都能引發對關係表的更新。
inverse只對set+one-to-many(或many-to-many)有效,對many-to-one, one-to-one無效。
cascade對關係標記都有效。
inverse對集合物件整體起作用,cascade對集合物件中的一個一個元素起作用,如果集合為空,那麼cascade不會引發關聯操作。
比如將集合物件置為null, school.setStudentSet(null)
inverse導致hibernate執行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?
cascade則不會執行對STUDENT表的關聯更新, 因為集合中沒有元素。
再比新增一個school, session.save(school)
inverse導致hibernate執行:
for( 對(school的每一個student ){
udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //將學生的school_id改為新的school的id
}
cascade導致hibernate執行:
for( 對school的每一個student ){
session.save(aStudent); //對學生執行save操作
}
extends:如果改變集合中的部分元素(比如新增一個元素),
inverse: hibernate先判斷哪些元素改變了,對改變的元素執行相應的sql
cascade: 它總是對集合中的每個元素執行關聯操作。
(在關聯操作中,hibernate會判斷操作的物件是否改變)
兩個起作用的時機不同:
cascade:在對主控方操作時,級聯發生。
inverse: 在flush時(commit會自動執行flush),對session中的所有set,hibernate判斷每個set是否有變化,
對有變化的set執行相應的sql,執行之前,會有個判斷:if( inverse == true ) return;
可以看出cascade在先,inverse在後。
inverse 對set + one-to-many 和 set + many-to-many 起的作用不同。hibernate生成的sql不同。
對one-to-many,hibernate對many方的資料庫表執行update語句。
對many-to-many, hibernate對關係表執行insert/update/delte語句,注意不是對many方的資料庫表而是關係表。
cascase 對set都是一致的,不管one-to-many還是many-to-many。都簡單地把操作傳遞到set中的每個元素。所以它總是更新many
方的資料庫表。
建議:只對set + many-to-many設定inverse=false,其他的標記不考慮inverse屬性,都設為inverse=true。
對cascade,一般對many-to-one,many-to-many,constrained=true的one-to-one 不設定級聯刪除。