? hibernate如何根據pojo來更新數據庫
在commit/flush之前hibernate不會對pojo對象作神秘的處理
在select查詢出pojo時hibernate根據字段屬性的對應關系用字段的值填充pojo的屬性
然後根據關系標記生成sql語句從relationTable中查詢出滿足條件的relationPojo並把這些relatinPojo
放到關系屬性中這個過程是機械的
在pojo對象被查出來後到commit(或flush)之前它將是一個普通的java對象hibernate不會做額外的手腳
比如不會限制你設置一個屬性的值為null或其它任何值
在集合類Set的add(object)操作時 不會改變object的值不會檢查參數object是否是一個pojo對象
設置mainPojo的一個橋屬性的值不會自動設置relationPojo的對應的橋屬性的值
執行sessiondelete(pojo)時pojo本身沒有變化他的屬性值也沒有變化
執行sessionsave(pojo)時如果pojo的id不是hibernate或數據庫生成則它的值沒有變化
如果pojo的id是hibernate或數據庫生成則hibernate會把id給pojo設上去
extend: 對lazy=true的sethibernate在進行set的操作(調用javautilSet中聲明的方法)時
會先inialize這個set僅此而已而inialize僅僅是從數據庫中撈出set的數據
如果一個set已經被inialize了那麼對它進行的操作就是javautilSet接口中定義的語義
另外如果id由hibernate來生成那麼在save(pojo)時hibernate會改變該pojo會設置它的id這
可能改變該pojo的hashCode詳細地討論見帖《》
mapping文件中標記的某些屬性及pojo對象的操作會對數據庫操作產生影響這些影響都是在commit時才會起作用
而在commit前pojo的狀態不受它們的影響
不過待commit之時將由hibernate完全掌控它好像知道pojo對象從創建到commit這中間的所有變化
關聯更新
關系標記對應的屬性是一個pojo或一個pojo的集合修改關系屬性的值能會導致更新mainTable表也可能會更新relationTable表
這種更新暫叫關聯更新
inverse屬性的作用(假定沒有設置cascade屬性)
只有集合標記(set/map/list/array/bag)才有inverse屬性
————不妨以標記set為例具體為一個地區(Address表)的學校(School表) addressschoolSet
set的inverse屬性決定是否把對set的改動反映到數據庫中去
inverse=false————反映inverse=true————不反映
inverse屬性默認為false
對<onetomany>和<manytomany>子標記這兩條都適用
不管是對set做什麼操作都適用
當inverse=false時hibernate如何將對set的改動反映到數據庫中
對set的操作主要有()新增元素 addressgetSchoolSet()add(oneSchool);
()刪除元素 addressgetSchoolSet()remove(oneSchool);
()刪除set addresssetSchoolSet(null);
()設新set addresssetSchoolSet( newSchoolSet);
()轉移set otherSchoolSet = otherAddressgetSchoolSet();
otherAddresssetSchoolSet(null);
addresssetSchoolSet(otherSchoolSet);
()改變set中元素的屬性的值 如果是改變key屬性這會導致異常
如果改變的是普通的屬性則hibernate認為set沒有變化(在後面可以看出緣由)
所以這種情形不予考慮
改變set後hibernate對數據庫的操作根據是<onetomany>關系還是<manytomany>關系而有不同
對onetomany對school set的改動會改變表SCHOOL中的數據:
#SCHOOL_ID是school表的主鍵SCHOOL_ADDRESS是school表中的地址欄位
#表School的外鍵為SCHOOL_ADDRESS它對應表Address的主鍵ADDRESS_ID
()insert oneSchool———— sqlInsertRowString:
update SCHOOL set SCHOOL_ADDRESS=? where SCHOOL_ID=?
(僅僅update foreignkey的值)
()delete oneSchool———— sqlDeleteRowString:
update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ID=?
(很奇怪把foreignkey設置為null不知道有什麼實際意義?)
()delete 屬於某一address的所有school ————sqlDeleteString
update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ADDRESS=?
()update ————sqlUpdateRowString no need
對manytomany對school set的改動會改變關系表ADDRESS_SCHOOL中的數據:
#地區————學校的關系為多對多的關系有點牽強只是為了方便與上面的onetomany作比較
#假設有一個關系表ADDRESS_SCHOOL有兩個字段ADDRESS_ID SCHOOL_ID
#這兩個字段分別對應ADDRESS和SCHOOL兩表的key
()insert的SQL語句為 insert into ADDRESS_SCHOOL(ADDRESS_ID SCHOOL_ID)
values(??)
()delete的SQL語句為 delete from ADDRESS_SCHOOL
where ADDRESS_ID=? AND SCHOOL_ID=?
()delete all的SQL語句為 delete from ADDRESS_SCHOOL
where ADDRESS_ID=?
()update的sql語句為 ————sqlUpdateRowString
update ADDRESS_SCHOOL set ADDRESS_ID=?
where ADDRESS_ID=? AND SCHOOL_ID=?
對set的操作()hibernate會執行()sqlInsertRowString
對set的操作()hibernate會執行()sqlDeleteRowString
對set的操作()hibernate會執行()sqlDeleteString
對set的操作()老的schoolSet因為沒有所屬的address所以被全部delete掉即先執行()sqlDeleteString
然後新增新的schoolSet即再執行sqlInsertRowString
對set的操作()實際上就是將set從一個pojo轉移到另一pojo
首先執行sqlDeleteString刪除掉otherAddress所屬的school
然後執行sqlDeleteString刪除掉address原先的school
最後執行sqlInsertRowString將otherSchoolSet新增給address
總結()對onetomany而言改變set會讓hibernate執行一系列的update語句 不會delete/insert數據
()對manytomany而言改變set只修改關系表的數據不會影響manytomany的另一方
()雖然onetomany和manytomany的數據庫操作不一樣但目的都是一個維護數據的一致性執行的sql都
只涉及到橋字段不會考慮或改變其他的字段所以對set的操作()是沒有效果地
extend:對list可能還會維護index字段
inverse與cascade沒有什麼關系互無牽扯
commit後這兩個屬性發揮作用的時機不同hibernate會根據對pojo對象的改動及cascade屬性的設置
生成一系列的Action比如UpdateActionDeleteActionInsertAction等每個Action都有execute方法以執行對應的sql語句
待所有這些Action都生成好了後hibernate再一起執行它們在執行sql前inverse屬性起作用
當inverse=true時不執行sql當inverse=false時執行sql
inverse的默認值為false所以inverse屬性默認會進行關聯更新
建議只對set + manytomany設置inverse=false其他的標記不考慮inverse屬性
糟糕的是不設置inverse屬性時inverse默認為false
級聯(cascade)屬性的作用
只有關系標記才有cascade屬性manytooneonetoone any
set(map bag idbag list array) + onetomany(manytomany)
級聯指的是當主控方執行操作時關聯對象(被動方)是否同步執行同一操作
pojo和它的關系屬性的關系就是主控方 被動方的關系如果關系屬性是一個set那麼被動方就是set中的一個一個元素
比如學校(School)有三個屬性地區(Address)校長(TheMaster)和學生(Set 元素為Student)
執行sessiondelete(school)時級聯決定是否執行sessiondelete(Address)sessiondelete(theMaster)
是否對每個aStudent執行sessiondelete(aStudent)
extend:這點和inverse屬性是有區別的見
一個操作因級聯cascade可能觸發多個關聯操作前一個操作叫主控操作後一個操作叫關聯操作
cascade屬性的可選值
all : 所有情況下均進行關聯操作
none所有情況下均不進行關聯操作這是默認值
saveupdate:在執行save/update/saveOrUpdate時進行關聯操作
delete在執行delete時進行關聯操作
具體執行什麼關聯操作是根據主控操作來的
主控操作 關聯操作
sessionsaveOrUpdate > sessionsaveOrUpdate (執行saveOrUpdate實際上會執行save或者update)
sessionsave > sessionsaveOrUpdate
sessionudpate > sessionsaveOrUpdate
sessiondelete > sessiondelete
主控操作和關聯操作的先後順序是先保存one再保存many先刪除many再刪除one先update主控方再update被動方
對於onetoone當其屬性constrained=false(默認值)時它可看作onetomany關系
當其屬性constrained=true時它可看作manytoone關系
對manytomany它可看作onetomany
比如學校(School)有三個屬性地區(Address)校長(TheMaster其constrained=false)和學生(Set 元素為Student)
當執行sessionsave(school)時
實際的執行順序為sessionsave(Address);
sessionsave(school);
sessionsave(theMaster);
for( 對每一個student ){
sessionsave(aStudent);
}
當執行sessiondelete(school)時
實際的執行順序為sessiondelete(theMaster);
for( 對每一個student ){
sessiondelete(aStudent);
}
sessiondelete(school);
sessiondelete(Address);
當執行sessionupdate(school)時
實際的執行順序為sessionupdate(school);
sessionsaveOrUpdate(Address);
sessionsaveOrUpdate(theMaster);
for( 對每一個student ){
sessionsaveOrUpdate(aStudent);
}
注意update操作因級聯引發的關聯操作為saveOrUpdate操作而不是update操作
saveOrUpdate與update的區別是前者根據操作對象是保存了還是沒有保存而決定執行update還是save
extends: 實際中刪除學校不會刪除地區即地區的cascade一般設為false
另外manytomany關系很少設置cascade=true而是設置inverse=false這個反映了cascade和inverse的區別見
cascade的默認值為false所以inverse屬性默認會進行關聯更新
總結級聯(cascade)就是操作一個對象時對它的屬性(其cascade=true)也進行這個操作
inverse和cascade的比較
這兩個屬性本身互不影響但起的作用有些類似都能引發對關系表的更新
inverse只對set+onetomany(或manytomany)有效對manytoone onetoone無效
cascade對關系標記都有效
inverse對集合對象整體起作用cascade對集合對象中的一個一個元素起作用如果集合為空那麼cascade不會引發關聯操作
比如將集合對象置為null schoolsetStudentSet(null)
inverse導致hibernate執行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?
cascade則不會執行對STUDENT表的關聯更新 因為集合中沒有元素
再比新增一個school sessionsave(school)
inverse導致hibernate執行
for( 對(school的每一個student ){
udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //將學生的school_id改為新的school的id
}
cascade導致hibernate執行
for( 對school的每一個student ){
sessionsave(aStudent); //對學生執行save操作
}
extends:如果改變集合中的部分元素(比如新增一個元素)
inverse: hibernate先判斷哪些元素改變了對改變的元素執行相應的sql
cascade: 它總是對集合中的每個元素執行關聯操作
(在關聯操作中hibernate會判斷操作的對象是否改變)
兩個起作用的時機不同
cascade在對主控方操作時級聯發生
inverse: 在flush時(commit會自動執行flush)對session中的所有sethibernate判斷每個set是否有變化
對有變化的set執行相應的sql執行之前會有個判斷if( inverse == true ) return;
可以看出cascade在先inverse在後
inverse 對set + onetomany 和 set + manytomany 起的作用不同hibernate生成的sql不同
對onetomanyhibernate對many方的數據庫表執行update語句
對manytomany hibernate對關系表執行insert/update/delte語句注意不是對many方的數據庫表而是關系表
cascase 對set都是一致的不管onetomany還是manytomany都簡單地把操作傳遞到set中的每個元素所以它總是更新many
方的數據庫表
建議只對set + manytomany設置inverse=false其他的標記不考慮inverse屬性都設為inverse=true
對cascade一般對manytoonemanytomanyconstrained=true的onetoone 不設置級聯刪除
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28321.html