<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 40, comments - 58, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    hibernate集合映射cascade和inverse詳解

    Posted on 2011-04-22 10:51 Astro.Qi 閱讀(235) 評論(0)  編輯  收藏 所屬分類: Hibernate

    1、到底在哪用cascade="..."?

    cascade屬性并不是多對多關系一定要用的,有了它只是讓我們在插入或刪除對像時更方便一些,只要在cascade的源頭上插入或是刪除,所有cascade的關系就會被自己動的插入或是刪除。便是為了能正確的cascade,unsaved-value是個很重要的屬性。Hibernate通過這個屬性來判斷一個對象應該save還是update,如果這個對象的id是unsaved-value的話,那說明這個對象不是persistence object要save(insert);如果id是非unsaved-value的話,那說明這個對象是persistence object(數據庫中已存在),只要update就行了。saveOrUpdate方法用的也是這個機制。

    2、到底在哪用inverse="ture"?

    inverse屬性默認是false的,就是說關系的兩端都來維護關系。這個意思就是說,如有一個Student, Teacher和TeacherStudent表,Student和Teacher是多對多對多關系,這個關系由TeacherStudent這個表來表現。那么什么時候插入或刪除TeacherStudent表中的記錄來維護關系呢?在用hibernate時,我們不會顯示的對TeacherStudent表做操作。對TeacherStudent的操作是hibernate幫我們做的。hibernate就是看hbm文件中指定的是"誰"維護關系,那個在插入或刪除"誰"時,就會處發對關系表的操作。前提是"誰"這個對象已經知道這個關系了,就是說關系另一頭的對象已經set或是add到"誰"這個對象里來了。前面說過inverse默認是false,就是關系的兩端都維護關系,對其中任一個操作都會處發對表系表的操作。當在關系的一頭,如Student中的bag或set中用了inverse="true"時,那就代表關系是由另一關維護的(Teacher)。就是說當這插入Student時,不會操作TeacherStudent表,即使Student已經知道了關系。只有當Teacher插入或刪除時才會處發對關系表的操作。所以,當關系的兩頭都用inverse="true"是不對的,就會導致任何操作都不處發對關系表的操作。當兩端都是inverse="false"或是default值是,在代碼對關系顯示的維護也是不對的,會導致在關系表中插入兩次關系。

    在一對多關系中inverse就更有意義了。在多對多中,在哪端inverse="true"效果差不多(在效率上)。但是在一對多中,如果要一方維護關系,就會使在插入或是刪除"一"方時去update"多"方的每一個與這個"一"的對象有關系的對象。而如果讓"多"方面維護關系時就不會有update操作,因為關系就是在多方的對象中的,直指插入或是刪除多方對象就行了。當然這時也要遍歷"多"方的每一個對象顯示的操作修關系的變化體現到DB中。不管怎樣說,還是讓"多"方維護關系更直觀一些。

    3、cascade和inverse有什么區別?

    可以這樣理解,cascade定義的是關系兩端對象到對象的級聯關系;而inverse定義的是關系和對象的級聯關系。

    all : 所有情況下均進行關聯操作。 
    none:所有情況下均不進行關聯操作。這是默認值。 
    save-update:在執行save/update/saveOrUpdate時進行關聯操作。 
    delete:在執行delete時進行關聯操作。

     

    all的意思是save-update + delete 
    all-delete-orphan 的意思是當對象圖中產生孤兒節點時,在數據庫中刪除該節點 
    all比較好理解,舉個例子說一下all-delete-orphan: 
    Category與Item是一對多的關系,也就是說Category類中有個Set類型的變量items. 
    舉個例子,現items中存兩個Item, item1,item2,如果定義關系為all-delete-orphan 
    當items中刪除掉一個item(比如用remove()方法刪除item1),那么被刪除的Item類實例 
    將變成孤兒節點,當執行category.update(),或session.flush()時 
    hibernate同步緩存和數據庫,會把數據庫中item1對應的記錄刪掉

    //////////////////////////////////////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////

    ?4. hibernate如何根據pojo來更新數據庫

    4.0  在commit/flush之前,hibernate不會對pojo對象作神秘的處理。
    4.0.1 在select查詢出pojo時,hibernate根據“字段--屬性”的對應關系,用字段的值填充pojo的屬性;
    然后根據“關系標記”生成sql語句從relationTable中查詢出滿足條件的relationPojo,并把這些relatinPojo
    放到“關系屬性”中。這個過程是機械的。

    4.0.2 在pojo對象被查出來后,到commit(或flush)之前,它將是一個普通的java對象,hibernate不會做額外的手腳。
    比如,不會限制你設置一個屬性的值為null或其它任何值
    在集合類Set的add(object)操作時, 不會改變object的值,不會檢查參數object是否是一個pojo對象
    設置mainPojo的一個“橋屬性”的值,不會自動設置relationPojo的對應的“橋屬性”的值。
    執行session.delete(pojo)時,pojo本身沒有變化,他的屬性值也沒有變化。
    執行session.save(pojo)時,如果pojo的id不是hibernate或數據庫生成,則它的值沒有變化。
      如果pojo的id是hibernate或數據庫生成,則hibernate會把id給pojo設上去。

    extend: 對lazy=true的set,hibernate在進行set的操作(調用java.util.Set中聲明的方法)時
    會先inialize這個set,僅此而已。而inialize僅僅是從數據庫中撈出set的數據。 
    如果一個set已經被inialize了,那么對它進行的操作就是java.util.Set接口中定義的語義。

    另外,如果id由hibernate來生成,那么在save(pojo)時,hibernate會改變該pojo,會設置它的id,這
    可能改變該pojo的hashCode,詳細地討論見帖《》

    mapping文件中標記的某些屬性及pojo對象的操作會對數據庫操作產生影響,這些影響都是在commit時才會起作用。
    而在commit前pojo的狀態不受它們的影響。

    不過,待commit之時,將由hibernate完全掌控,它好像知道pojo對象從創建到commit這中間的所有變化。


    4.01. 關聯更新
    "關系標記"對應的屬性是一個pojo或一個pojo的集合,修改“關系屬性”的值能會導致更新mainTable表,也可能會更新relationTable表。

    這種更新暫叫“關聯更新”。


    4.1.inverse屬性的作用(假定沒有設置cascade屬性) 
    4.1.1 “只有集合標記(set/map/list/array/bag)才有inverse屬性”。
    ————不妨以標記set為例,具體為“一個地區(Address表)的學校(School表)” -- address.schoolSet。

    4.1.2 “set的inverse屬性決定是否把對set的改動反映到數據庫中去。
    inverse=false————反映;inverse=true————不反映”
    inverse屬性默認為false

    對<one-to-many>和<many-to-many>子標記,這兩條都適用。
    不管是對set做什么操作,4.1.2都適用。

    4.1.3當inverse=false時,hibernate如何將對set的改動反映到數據庫中:

    對set的操作主要有:(1)新增元素 address.getSchoolSet().add(oneSchool);
    (2)刪除元素 address.getSchoolSet().remove(oneSchool);
    (3)刪除set  address.setSchoolSet(null);
    (4)設新set  address.setSchoolSet( newSchoolSet);
    (5)轉移set  otherSchoolSet = otherAddress.getSchoolSet();
      otherAddress.setSchoolSet(null);
      address.setSchoolSet(otherSchoolSet);
    (6)改變set中元素的屬性的值  如果是改變key屬性,這會導致異常
      如果改變的是普通的屬性,則hibernate認為set沒有變化(在后面可以看出緣由)。
      所以這種情形不予考慮。
      
    改變set后,hibernate對數據庫的操作根據是<one-to-many>關系還是<many-to-many>關系而有不同。

    對one-to-many,對school set的改動,會改變表SCHOOL中的數據:
      #SCHOOL_ID是school表的主鍵,SCHOOL_ADDRESS是school表中的地址欄位
      #表School的外鍵為SCHOOL_ADDRESS,它對應表Address的主鍵ADDRESS_ID
    (11)insert oneSchool———— sqlInsertRowString: 
    update SCHOOL set SCHOOL_ADDRESS=? where SCHOOL_ID=? 
    (僅僅update foreign-key的值。)
    (22)delete oneSchool———— sqlDeleteRowString: 
    update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ID=?
    (很奇怪,把foreign-key設置為null不知道有什么實際意義?)
    (33)delete 屬于某一address的所有school ————sqlDeleteString:
    update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ADDRESS=?
    (44)update ————sqlUpdateRowString:"", no need

    對many-to-many,對school set的改動,會改變關系表ADDRESS_SCHOOL中的數據:
    #“地區————學校”的關系為多對多的關系有點牽強,只是為了方便與上面的one-to-many作比較
    #假設有一個關系表ADDRESS_SCHOOL,有兩個字段ADDRESS_ID, SCHOOL_ID,
    #這兩個字段分別對應ADDRESS和SCHOOL兩表的key
    (11)insert的SQL語句為: insert into ADDRESS_SCHOOL(ADDRESS_ID, SCHOOL_ID) 
    values(?,?)
    (22)delete的SQL語句為: delete from ADDRESS_SCHOOL 
    where ADDRESS_ID=? AND SCHOOL_ID=?
    (33)delete all的SQL語句為: delete from ADDRESS_SCHOOL
    where ADDRESS_ID=?
    (44)update的sql語句為 ————sqlUpdateRowString:
    update ADDRESS_SCHOOL set ADDRESS_ID=?
    where ADDRESS_ID=? AND SCHOOL_ID=?

    對set的操作(1),hibernate會執行(11)sqlInsertRowString
    對set的操作(2),hibernate會執行(22)sqlDeleteRowString
    對set的操作(3),hibernate會執行(33)sqlDeleteString
    對set的操作(4),老的schoolSet因為沒有所屬的address,所以被全部delete掉,即先執行(33)sqlDeleteString
    然后新增新的schoolSet,即再執行sqlInsertRowString
    對set的操作(5),實際上就是將set從一個pojo轉移到另一pojo:
    首先,執行sqlDeleteString,刪除掉otherAddress所屬的school
    然后,執行sqlDeleteString,刪除掉address原先的school
    最后,執行sqlInsertRowString,將otherSchoolSet新增給address

    總結:(1)對one-to-many而言,改變set,會讓hibernate執行一系列的update語句, 不會delete/insert數據
    (2)對many-to-many而言,改變set,只修改關系表的數據,不會影響many-to-many的另一方。
    (3)雖然one-to-many和many-to-many的數據庫操作不一樣,但目的都是一個:維護數據的一致性。執行的sql都
    只涉及到“橋字段”,不會考慮或改變其他的字段,所以對set的操作(6)是沒有效果地。
    extend:對list,可能還會維護index字段。

    4.1.4 “inverse與cascade沒有什么關系,互無牽扯。”
    commit后,這兩個屬性發揮作用的時機不同,hibernate會根據對pojo對象的改動,及cascade屬性的設置,
    生成一系列的Action,比如UpdateAction,DeleteAction,InsertAction等,每個Action都有execute方法以執行對應的sql語句。
    待所有這些Action都生成好了后,hibernate再一起執行它們,在執行sql前,inverse屬性起作用,
    當inverse=true時,不執行sql;當inverse=false時,執行sql。

    4.1.5 inverse的默認值為false,所以inverse屬性默認會進行“關聯更新”。

    4.1.6 建議:只對set + many-to-many設置inverse=false,其他的標記不考慮inverse屬性。
       糟糕的是,不設置inverse屬性時,inverse默認為false。

    4.2. 級聯(cascade)屬性的作用: 
    4.2.1 只有“關系標記”才有cascade屬性:many-to-one,one-to-one ,any, 
    set(map, bag, idbag, list, array) + one-to-many(many-to-many)

    4.2.2 級聯指的是當主控方執行操作時,關聯對象(被動方)是否同步執行同一操作。
    pojo和它的關系屬性的關系就是“主控方 -- 被動方”的關系,如果關系屬性是一個set,那么被動方就是set中的一個一個元素,。
    比如:學校(School)有三個屬性:地區(Address),校長(TheMaster)和學生(Set, 元素為Student)
    執行session.delete(school)時,級聯決定是否執行session.delete(Address),session.delete(theMaster),
    是否對每個aStudent執行session.delete(aStudent)。

    extend:這點和inverse屬性是有區別的。見4.3.

    4.2.3 一個操作因級聯cascade可能觸發多個關聯操作。前一個操作叫“主控操作”,后一個操作叫“關聯操作”。
    cascade屬性的可選值:
    all : 所有情況下均進行關聯操作。
    none:所有情況下均不進行關聯操作。這是默認值。
    save-update:在執行save/update/saveOrUpdate時進行關聯操作。
    delete:在執行delete時進行關聯操作。 

    具體執行什么“關聯操作”是根據“主控操作”來的:
      “主控操作”         “關聯操作”
    session.saveOrUpdate --> session.saveOrUpdate (執行saveOrUpdate實際上會執行save或者update)
    session.save ----> session.saveOrUpdate
    session.udpate --> session.saveOrUpdate
    session.delete --> session.delete

    4.2.4 主控操作和關聯操作的先后順序是“先保存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

    4.2.6 cascade的默認值為false,所以inverse屬性默認會進行“關聯更新”。

    4.2.7 總結:級聯(cascade)就是操作一個對象時,對它的屬性(其cascade=true)也進行這個操作。


    4.3 inverse和cascade的比較
    這兩個屬性本身互不影響,但起的作用有些類似,都能引發對關系表的更新。

    4.3.1 inverse只對set+one-to-many(或many-to-many)有效,對many-to-one, one-to-one無效。
      cascade對關系標記都有效。
      
    4.3.2 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會判斷操作的對象是否改變)

    4.3.2 兩個起作用的時機不同:
    cascade:在對主控方操作時,級聯發生。
    inverse: 在flush時(commit會自動執行flush),對session中的所有set,hibernate判斷每個set是否有變化,
    對有變化的set執行相應的sql,執行之前,會有個判斷:if( inverse == true ) return;

    可以看出cascade在先,inverse在后。

    4.3.3 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
    方的數據庫表。

    4.3.4 建議:只對set + many-to-many設置inverse=false,其他的標記不考慮inverse屬性,都設為inverse=true。
       
       對cascade,一般對many-to-one,many-to-many,constrained=true的one-to-one 不設置級聯刪除。
    主站蜘蛛池模板: 亚洲精品美女久久777777| 亚洲精品国产免费| 国产免费阿v精品视频网址| 亚洲AV无码一区二区三区系列| 84pao国产成视频免费播放| 亚洲av永久无码一区二区三区| 亚洲精品亚洲人成在线观看下载 | 免费国产黄网站在线观看可以下载| 亚洲一级毛片视频| 久久久久亚洲AV无码专区桃色| h片在线免费观看| 五月天婷婷免费视频| 亚洲最大免费视频网| 免费A级毛片无码久久版| 日韩精品无码一区二区三区免费| 亚洲精品无码永久在线观看男男| 国产AV无码专区亚洲AV漫画| 免费精品人在线二线三线区别 | 免费人成在线观看网站视频| 日本免费一区二区三区 | 67pao强力打造国产免费| 国产亚洲一卡2卡3卡4卡新区| 亚洲国产精品一区二区久久| 免费一级国产生活片| 野花高清在线观看免费3中文| 国产在线观看免费av站| 久久亚洲精品无码网站| 内射干少妇亚洲69XXX| 亚洲一区日韩高清中文字幕亚洲| 手机在线毛片免费播放| 久久香蕉国产线看免费| 一区二区三区免费在线视频| 亚洲精品自偷自拍无码| 亚洲综合小说久久另类区| 国产亚洲精品福利在线无卡一| 欧洲精品免费一区二区三区| 亚洲免费观看网站| 无人在线观看免费高清| 你懂的免费在线观看| 一级做a爰片久久免费| 国产产在线精品亚洲AAVV|