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

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

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

    空間站

    北極心空

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks
    Hibernate的檢索策略包括類級別檢索策略和關(guān)聯(lián)級別檢索策略。

      類級別檢索策略有立即檢索和延遲檢索,默認(rèn)的檢索策略是立即檢索。在Hibernate映射文件中,通過在<class>上配置lazy屬性來確定檢索策略。對于Session的檢索方式,類級別檢索策略僅適用于load方法;也就說,對于get、qurey檢索,持久化對象都會被立即加載而不管lazy是false還是true.一般來說,我們檢索對象就是要訪問它,因此立即檢索是通常的選擇。由于load方法在檢索不到對象時會拋出異常(立即檢索的情況下),因此我個人并不建議使用load檢索;而由于<class>中的lazy屬性還影響到多對一及一對一的檢索策略,因此使用load方法就更沒必要了。

      關(guān)聯(lián)級別檢索策略有立即檢索、延遲檢索和迫切左外連接檢索。對于關(guān)聯(lián)級別檢索,又可分為一對多和多對多、多對一和一對一兩種情況討論。

      一對多和多對多關(guān)聯(lián)關(guān)系一般使用<set>配置。<set>有l(wèi)azy和outer-join屬性,它們的不同取值絕對了檢索策略。

      1)立即檢索:這是一對多默認(rèn)的檢索策略,此時lazy=false,outer-join=false.盡管這是默認(rèn)的檢索策略,但如果關(guān)聯(lián)的集合是無用的,那么就不要使用這種檢索方式。

      2)延遲檢索:此時lazy=true,outer-join=false(outer-join=true是無意義的),這是優(yōu)先考慮的檢索方式。

      3)迫切左外連接檢索:此時 lazy=false,outer-join=true,這種檢索策略只適用于依靠id檢索方式(load、get),而不適用于query的集合檢索(它會采用立即檢索策略)。相比于立即檢索,這種檢索策略減少了一條sql語句,但在Hibernate中,只能有一個<set>配置成 outer-join=true.

      多對一和一對一檢索策略一般使用<many-to-one>、<one-to-one>配置。<many-to-one>中需要配置的屬性是 outer-join,同時還需要配置one端關(guān)聯(lián)的<class>的lazy屬性(配置的可不是<many-to-one>中的lazy哦),它們的組合后的檢索策略如下:

      1) outer-join=auto:這是默認(rèn)值,如果lazy=true為延遲檢索,如果lazy=false為迫切左外連接檢索。

      2) outer-join=true,無關(guān)于lazy,都為迫切左外連接檢索。

      3) outer-join=false,如果lazy=true為延遲檢索,否則為立即檢索。

      可以看到,在默認(rèn)的情況下(outer-join=auto,lazy=false),對關(guān)聯(lián)的one端對象Hibernate采用的迫切左外連接檢索。依我看,很多情況下,我們并不需要加載one端關(guān)聯(lián)的對象(很可能我們需要的僅僅是關(guān)聯(lián)對象的id);另外,如果關(guān)聯(lián)對象也采用了迫切左外連接檢索,就會出現(xiàn)select語句中有多個外連接表,如果個數(shù)多的話會影響檢索性能,這也是為什么Hibernate通過hibernate.max_fetch_depth屬性來控制外連接的深度。對于迫切左外連接檢索,query的集合檢索并不適用,它會采用立即檢索策略。

      對于檢索策略,需要根據(jù)實際情況進(jìn)行選擇。對于立即檢索和延遲檢索,它們的優(yōu)點在于select語句簡單(每張表一條語句)、查詢速度快,缺點在于關(guān)聯(lián)表時需要多條select語句,增加了訪問數(shù)據(jù)庫的頻率。因此在選擇即檢索和延遲檢索時,可以考慮使用批量檢索策略來減少select語句的數(shù)量(配置batch-size屬性)。對于切左外連接檢索,優(yōu)點在于select較少,但缺點是select語句的復(fù)雜度提高,多表之間的關(guān)聯(lián)會是很耗時的操作。另外,配置文件是死的,但程序是活的,可以根據(jù)需要在程序里顯示的指定檢索策略(可能經(jīng)常需要在程序中顯示指定迫切左外連接檢索)。為了清楚檢索策略的配置效果如何,可以配置show_sql屬性查看程序運行時Hibernate執(zhí)行的sql語句。



    fetch參數(shù)指定了關(guān)聯(lián)對象抓取的方式是select查詢還是join查詢,select方式時先查詢返回要查詢的主體對象(列表),再根據(jù)關(guān)聯(lián)外鍵id,每一個對象發(fā)一個select查詢,獲取關(guān)聯(lián)的對象,形成n+1次查詢;
    而join方式,主體對象和關(guān)聯(lián)對象用一句外鍵關(guān)聯(lián)的sql同時查詢出來,不會形成多次查詢。
    如果你的關(guān)聯(lián)對象是延遲加載的,它當(dāng)然不會去查詢關(guān)聯(lián)對象。
    另外,在hql查詢中配置文件中設(shè)置的join方式是不起作用的(而在所有其他查詢方式如get、criteria或再關(guān)聯(lián)獲取等等都是有效的),會使用select方式,除非你在hql中指定join fetch某個關(guān)聯(lián)對象。

     

    fetch策略用于定義 get/load一個對象時,如何獲取非lazy的對象/集合。 這些參數(shù)在Query中無效。

    fetch策略用于定義 get/load一個對象時,如何獲取非lazy的對象/集合。 這些參數(shù)在Query中無效。

    在某種特殊的場合下,fetch在hql中還是起作用的。
    例如
    現(xiàn)有message(回帖)-->topic(主貼)-->forum(版塊) 的多級many-to-one結(jié)構(gòu):
    第一級:message-->topic many-to-one配置lazy="false" fetch="join"
    第二級:topic-->forum many-to-one配置lazy="false" fetch="join"

    這時如果"from message",則第二級:topic-->forum中的fetch策略會起作用 

     

    查詢抓取(默認(rèn)的)在N+1查詢的情況下是極其脆弱的,因此我們可能會要求在映射文檔中定義使用連接抓取:

     

    <set name="permissions"
    fetch="join">
    <key column="userId"/>
    <one-to-many class="Permission"/>
    </set
    <many-to-one name="mother" class="Cat" fetch="join"/>
    在映射文檔中定義的抓取策略將會有產(chǎn)生以下影響:

    通過get()或load()方法取得數(shù)據(jù)。

    只有在關(guān)聯(lián)之間進(jìn)行導(dǎo)航時,才會隱式的取得數(shù)據(jù)(延遲抓取)。

    條件查詢

    在映射文檔中顯式的聲明 連接抓取做為抓取策略并不會影響到隨后的HQL查詢。

    通常情況下,我們并不使用映射文檔進(jìn)行抓取策略的定制。更多的是,保持其默認(rèn)值,然后在特定的事務(wù)中, 使用HQL的左連接抓取(left join fetch) 對其進(jìn)行重載。這將通知 Hibernate在第一次查詢中使用外部關(guān)聯(lián)(outer join),直接得到其關(guān)聯(lián)數(shù)據(jù)。 在條件查詢 API中,應(yīng)該調(diào)用 setFetchMode(FetchMode.JOIN)語句。

    其實這并不能說明hql能夠按照配置文件設(shè)置的join進(jìn)行抓取,這時 第二級:topic-->forum 的抓取其實已經(jīng)和hql沒有關(guān)系了,因為前面已經(jīng)產(chǎn)生了另一個select方式的抓取語句。
    而是對象的關(guān)聯(lián)獲取,假如查詢message時topic是設(shè)置為延遲加載的,那么在后面獲取message.topic時,如topic.forum不延遲加載,那么topic-->forum會實現(xiàn)配置的join方式的抓取,這個顯然和hql查詢沒有關(guān)系。



    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1755222

     

    hibernate集合映射inverse和cascade詳解

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

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

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

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

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

    3、cascade和inverse有什么區(qū)別?

    可以這樣理解,cascade定義的是關(guān)系兩端對象到對象的級聯(lián)關(guān)系;而inverse定義的是關(guān)系和對象的級聯(lián)關(guān)系。

    all : 所有情況下均進(jìn)行關(guān)聯(lián)操作。
    none:所有情況下均不進(jìn)行關(guān)聯(lián)操作。這是默認(rèn)值。
    save-update:在執(zhí)行save/update/saveOrUpdate時進(jìn)行關(guān)聯(lián)操作。
    delete:在執(zhí)行delete時進(jìn)行關(guān)聯(lián)操作。

     

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

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

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

    ?4. hibernate如何根據(jù)pojo來更新數(shù)據(jù)庫

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

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

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

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

    mapping文件中標(biāo)記的某些屬性及pojo對象的操作會對數(shù)據(jù)庫操作產(chǎn)生影響,這些影響都是在commit時才會起作用。
    而在commit前pojo的狀態(tài)不受它們的影響。

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


    4.01. 關(guān)聯(lián)更新
    "關(guān)系標(biāo)記"對應(yīng)的屬性是一個pojo或一個pojo的集合,修改“關(guān)系屬性”的值能會導(dǎo)致更新mainTable表,也可能會更新relationTable表。

    這種更新暫叫“關(guān)聯(lián)更新”。


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

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

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

    4.1.3當(dāng)inverse=false時,hibernate如何將對set的改動反映到數(shù)據(jù)庫中:

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

    對one-to-many,對school set的改動,會改變表SCHOOL中的數(shù)據(jù):
      #SCHOOL_ID是school表的主鍵,SCHOOL_ADDRESS是school表中的地址欄位
      #表School的外鍵為SCHOOL_ADDRESS,它對應(yīng)表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設(shè)置為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的改動,會改變關(guān)系表ADDRESS_SCHOOL中的數(shù)據(jù):
    #“地區(qū)————學(xué)校”的關(guān)系為多對多的關(guān)系有點牽強,只是為了方便與上面的one-to-many作比較
    #假設(shè)有一個關(guān)系表ADDRESS_SCHOOL,有兩個字段ADDRESS_ID, SCHOOL_ID,
    #這兩個字段分別對應(yīng)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會執(zhí)行(11)sqlInsertRowString
    對set的操作(2),hibernate會執(zhí)行(22)sqlDeleteRowString
    對set的操作(3),hibernate會執(zhí)行(33)sqlDeleteString
    對set的操作(4),老的schoolSet因為沒有所屬的address,所以被全部delete掉,即先執(zhí)行(33)sqlDeleteString
    然后新增新的schoolSet,即再執(zhí)行sqlInsertRowString
    對set的操作(5),實際上就是將set從一個pojo轉(zhuǎn)移到另一pojo:
    首先,執(zhí)行sqlDeleteString,刪除掉otherAddress所屬的school
    然后,執(zhí)行sqlDeleteString,刪除掉address原先的school
    最后,執(zhí)行sqlInsertRowString,將otherSchoolSet新增給address

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

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

    4.1.5 inverse的默認(rèn)值為false,所以inverse屬性默認(rèn)會進(jìn)行“關(guān)聯(lián)更新”。

    4.1.6 建議:只對set + many-to-many設(shè)置inverse=false,其他的標(biāo)記不考慮inverse屬性。
       糟糕的是,不設(shè)置inverse屬性時,inverse默認(rèn)為false。

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

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

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

    4.2.3 一個操作因級聯(lián)cascade可能觸發(fā)多個關(guān)聯(lián)操作。前一個操作叫“主控操作”,后一個操作叫“關(guān)聯(lián)操作”。
    cascade屬性的可選值:
    all : 所有情況下均進(jìn)行關(guān)聯(lián)操作。
    none:所有情況下均不進(jìn)行關(guān)聯(lián)操作。這是默認(rèn)值。
    save-update:在執(zhí)行save/update/saveOrUpdate時進(jìn)行關(guān)聯(lián)操作。
    delete:在執(zhí)行delete時進(jìn)行關(guān)聯(lián)操作。

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

    4.2.4 主控操作和關(guān)聯(lián)操作的先后順序是“先保存one,再保存many;先刪除many,再刪除one;先update主控方,再update被動方”
    對于one-to-one,當(dāng)其屬性constrained="false"(默認(rèn)值)時,它可看作one-to-many關(guān)系;
       當(dāng)其屬性constrained="true"時,它可看作many-to-one關(guān)系;
    對many-to-many,它可看作one-to-many。

    比如:學(xué)校(School)有三個屬性:地區(qū)(Address),校長(TheMaster,其constrained="false")和學(xué)生(Set, 元素為Student)
    當(dāng)執(zhí)行session.save(school)時,
    實際的執(zhí)行順序為:session.save(Address);
    session.save(school);
    session.save(theMaster);
    for( 對每一個student ){
    session.save(aStudent);
    }

    當(dāng)執(zhí)行session.delete(school)時,
    實際的執(zhí)行順序為:session.delete(theMaster);
    for( 對每一個student ){
    session.delete(aStudent);
    }
    session.delete(school);
    session.delete(Address);

    當(dāng)執(zhí)行session.update(school)時,
    實際的執(zhí)行順序為:session.update(school);
    session.saveOrUpdate(Address);
    session.saveOrUpdate(theMaster);
    for( 對每一個student ){
    session.saveOrUpdate(aStudent);
    }
    注意:update操作因級聯(lián)引發(fā)的關(guān)聯(lián)操作為saveOrUpdate操作,而不是update操作。
    saveOrUpdate與update的區(qū)別是:前者根據(jù)操作對象是保存了還是沒有保存,而決定執(zhí)行update還是save

    extends: 實際中,刪除學(xué)校不會刪除地區(qū),即地區(qū)的cascade一般設(shè)為false
    另外,many-to-many關(guān)系很少設(shè)置cascade=true,而是設(shè)置inverse=false。這個反映了cascade和inverse的區(qū)別。見4.3

    4.2.6 cascade的默認(rèn)值為false,所以inverse屬性默認(rèn)會進(jìn)行“關(guān)聯(lián)更新”。

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


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

    4.3.1 inverse只對set+one-to-many(或many-to-many)有效,對many-to-one, one-to-one無效。
      cascade對關(guān)系標(biāo)記都有效。
     
    4.3.2 inverse對集合對象整體起作用,cascade對集合對象中的一個一個元素起作用,如果集合為空,那么cascade不會引發(fā)關(guān)聯(lián)操作。
    比如將集合對象置為null, school.setStudentSet(null)
    inverse導(dǎo)致hibernate執(zhí)行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?
    cascade則不會執(zhí)行對STUDENT表的關(guān)聯(lián)更新, 因為集合中沒有元素。

    再比新增一個school, session.save(school)
    inverse導(dǎo)致hibernate執(zhí)行:
    for( 對(school的每一個student ){
    udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //將學(xué)生的school_id改為新的school的id
    }
    cascade導(dǎo)致hibernate執(zhí)行:
    for( 對school的每一個student ){
    session.save(aStudent); //對學(xué)生執(zhí)行save操作
    }

    extends:如果改變集合中的部分元素(比如新增一個元素),
    inverse: hibernate先判斷哪些元素改變了,對改變的元素執(zhí)行相應(yīng)的sql
    cascade: 它總是對集合中的每個元素執(zhí)行關(guān)聯(lián)操作。
    (在關(guān)聯(lián)操作中,hibernate會判斷操作的對象是否改變)

    4.3.2 兩個起作用的時機不同:
    cascade:在對主控方操作時,級聯(lián)發(fā)生。
    inverse: 在flush時(commit會自動執(zhí)行flush),對session中的所有set,hibernate判斷每個set是否有變化,
    對有變化的set執(zhí)行相應(yīng)的sql,執(zhí)行之前,會有個判斷: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方的數(shù)據(jù)庫表執(zhí)行update語句。
      對many-to-many, hibernate對關(guān)系表執(zhí)行insert/update/delte語句,注意不是對many方的數(shù)據(jù)庫表而是關(guān)系表。
     
      cascase 對set都是一致的,不管one-to-many還是many-to-many。都簡單地把操作傳遞到set中的每個元素。所以它總是更新many
    方的數(shù)據(jù)庫表。

    4.3.4 建議:只對set + many-to-many設(shè)置inverse=false,其他的標(biāo)記不考慮inverse屬性,都設(shè)為inverse=true。
      
       對cascade,一般對many-to-one,many-to-many,constrained=true的one-to-one 不設(shè)置級聯(lián)刪除。
     
     


    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1782982

    posted on 2007-10-17 13:22 蘆葦 閱讀(1371) 評論(0)  編輯  收藏 所屬分類: Hibernate
    主站蜘蛛池模板: 免费无码成人AV在线播放不卡| 亚洲色av性色在线观无码| 欧美日韩国产免费一区二区三区 | 久久狠狠躁免费观看2020| 美女无遮挡免费视频网站| 97久久国产亚洲精品超碰热| 亚洲av永久无码制服河南实里| 免费v片在线观看品善网| 天天天欲色欲色WWW免费| 曰曰鲁夜夜免费播放视频| 国产麻豆成人传媒免费观看| xvideos永久免费入口| 日韩色日韩视频亚洲网站| 亚洲欧洲精品成人久久曰| 亚洲人成网站在线观看播放青青| 亚洲AV无码1区2区久久| 国产成人亚洲精品青草天美| 日韩一卡2卡3卡4卡新区亚洲| 四虎在线播放免费永久视频| 日韩免费a级在线观看| 在线播放免费播放av片| 人妻视频一区二区三区免费| 国产在线观看片a免费观看| free哆啪啪免费永久| 精品无码人妻一区二区免费蜜桃| 久久国产免费观看精品| a在线观看免费视频| 国产午夜精品免费一区二区三区 | 一本色道久久综合亚洲精品| 亚洲精品国产福利一二区| 亚洲黄片毛片在线观看| 亚洲国产成人a精品不卡在线| 亚洲高清无码综合性爱视频| 国产精品亚洲玖玖玖在线观看| 五月天婷亚洲天综合网精品偷| 免费亚洲视频在线观看| 亚洲国产成人爱av在线播放| 亚洲成人影院在线观看| 亚洲午夜久久久影院| 亚洲好看的理论片电影| 亚洲午夜精品在线|