<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:47 Astro.Qi 閱讀(260) 評論(0)  編輯  收藏 所屬分類: Hibernate

    在學習Hibernate的過程中最不好理解的就是這兩個屬性了。
    (我當初學習Hibernate的時候,發現網上介紹這兩個屬性的文章倒是不少,但是,居然有好多都是轉帖。。。還有的就是 照書搬~~-_-!!!)。。。

    據個例子:書上說inverse=false時,由主控方維持關系。。。
    由于我也是初學者。。。再加上語文水平偏低。。。不理解“維持關系是啥意思”囧~

    提示:
    (1)如果:您不了解Hibernate的one-to-many或many-to-one的概念。

    (2)如果:你不了解Hibernate的“自由態”“持久態”“游離態”的概念。

    (3)如果:您不了解Hibernate中的“臟數據”的概念。

    (4)如果:您對Hibernate中Session緩存,沒有初步了解的話。
    (在Hibernate中調用save進行存儲數據的時候,并不是馬上就對數據庫進行insert操作,而是會將其“數據對象(vo)”納入Hibernate的Session緩存。)

    在上面的4條提示中,如果您對其中的某一條,不是很清楚的話。希望請先了解有關知識。
    否則,可能您將 “無法或很難”理解 cascade 或 inverse 這2個屬性。

    首相,cascade 與 inverse 這兩個屬性,其實是完全不同的兩個東西,想要了解他們各自的“用途與區別”,詳見如下介紹:

    這里有兩個表:

    (1)class   (班級表)
    相應字段:
    cid    varchar(32) 主鍵 not-null (班級id)
    cname varchar(16)      not-null (班級名稱)   

    (2)student (學生表)
    相應字段:
    sid    varchar(32) 主鍵 not-null (學生id)
    sname varchar(16)      not-null (學生姓名)
    class_id varchar(32)   not-null (學生所屬班級)

    一個班級(class)對應多個學生(student),所以班級表(class)就是“one-to-many”端
    反之student就是many-to-one

    //--------Class類的代碼--------
    public class Class implements.....
    {
    private cId = "";
    private cName = "";
    private students = java.util.HashMap();
    // 省略對應的 geter setter
    }
    //--------Class.hbm.xml--------
    <hibernate-mapping>
    <class name="lcx.vo.Class" table="class"
       catalog="demo">
       <id name="cid" type="java.lang.String">
        <column name="cid" length="32" />
        <generator class="uuid.hex" />
       </id>
       <property name="name" type="java.lang.String">
        <column name="cname" length="16" not-null="true" />
       </property>
      
       <set name="students" table="student" cascade="save-update">
        <key column="class" />
        <one-to-many class="lcx.vo.Student" />
       </set> 
    </class>
    </hibernate-mapping>

    //--------Student類的代碼;*******
    public class Student implements.....
    {
    private sId = "";
    private sName = "";
    private Class class = null;
    // 省略對應的 geter setter
    }
    // Student.hbm.xml
    <hibernate-mapping>
    <class name="lcx.vo.Student" table="student" catalog="demo">
       <id name="cid" type="java.lang.String">
        <column name="sid" length="32" />
        <generator class="uuid.hex" />
       </id>
       <many-to-one name="class" 
        class="lcx.vo.Class"
        column="class_id" 
        not-null="true" 
       />   
    </class>
    </hibernate-mapping>

    (一) cascade 的介紹:
    當Hibernate持久化一個“臨時對象(也叫自由態對象)”時,在默認的情況下(即:沒有設置cascade屬性或cascade=none時),Hibernate不會自動“持久化他所關聯”的其他臨時對象。

    上面這些話是什么意思呢? 什么叫不會自動 “持久化”關聯的臨時對象呢?

    看如下代碼:

    // 創建一個 臨時對象(也叫自由態對象) 
    // 也就是說這個 class 沒有被Hibernate納入Session緩存管理。
    Class class = new Class();
    //class.id 為自動生成
    class.setName("一年級1班");

    Student stu = new Student();
    //student.id 為自動生成
    stu.setName("小白兔");
    stu.setClass(class);

    // 關鍵就是這里。。。
    class.getStudents().add(stu);

    session.save(class);
    // 提交

    // 注意: Class.hbm.xml文件中,cascade="save-update"并且也沒有設置inverse屬性,也就是說inverse=false;
    // 此時如果你開啟了Hibernate的顯示HQL語句功能,那么控制臺將會顯示如下3條HQL:

    //----------------------------------------********
    insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年級1班)
    insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔, 66666666666666666666666666666666)
    update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888
    //----------------------------------------********

    那么為什么會出現,這3條HQL語句呢,我們來一一分析一下:

    第1條HQL語句:
    其實第一條HQL比較好理解,
    當我們調用 session.save(class) 后,在Hibernate進行提交的時候,
    會發現“有”一條“新”的數據要插入(insert),所以就往class表中,插入了這條新的class記錄。

    第2條HQL語句:
    注意問題就在這里:
    這里為什么又出現了一條insert語句呢?而且還是向student表中插入數據。
    我們在上面的代碼中,并沒有編寫類似“session.save(student)”這樣的語句啊。
    這是為什么呢?
    其實原因,是這么回事:因為我們在class端,設置了"級聯更新"(即:cascade="save-update"),
    也就是說,當Hibernate在向class表中插入“新”對象記錄時,會檢查“Class對象”所關聯的屬性(就是<set>對應的屬性),是否發生過變化,如果發生了變化,就按照“級聯屬性(cascade)”所設定的內容
    進行操作。

    上面講的這句話到底是什么意思呢?
    用你們“人”話說,就是:
    因為調用了 class.getStudents().add(stu);
    所以,在Hibernate在進行插入 class對象的時候,發現class對象,所關聯的集合中,有一條
    “自由態”的對象,而又因為class端設置了“級聯屬性cascade”,所以,在插入這條 “新class對象”時,也一同把他內部的那些,還屬于“自由態”的其他對象,也一同插入到,他們所對應的表中去了。

    還是不明白的話。。。可以看看。孫衛琴的《精通Hibernate》,在書上的第149頁有。
    但是關于inverse的介紹。。。寫的就有些書面化了,如果語文不好的話。。。就難懂咯~

    第3條HQL語句:
    第三條HQL語句是一條update語句,是不是覺得,很莫名其妙。。。。
    Hibernate大腦進水了吧,怎么吃飽了撐得,重復更新記錄啊啊啊啊啊
    假如:我們把 class端的配置文檔中的 invser屬性設置為true(即:inverse=true)
    在執行上面的程序,發現,就變成2條insert語句啦。。。。。(update沒啦。。。)
    看來第三條的update語句和inverse有著密切的關系(他兩有一腿~)。

    所以我們下邊,就來介紹一下inverse屬性:

    當調用 Class.getStudents().add(stu)方法,進行添加操作時, 
    (即:向 "這個Class對象"所屬的“集合 (也就是調用getStudents方法所返回的那個Set集合)”中添加一個Student(即 add(stu)),也就是說,這個“新”添加的Student對象(stu), 
    他的Student.class_id字段“必須”,要等于“被添加方Class”的主鍵(即:Class.cid)。 
    從“數據庫”層面來講,也就是說,這個“新”添加的“Student”的class_id字段,必須要與“Class”的cid字段,存在"主外鍵關聯"。)

    正因為如此:所以Hibernate“怕” 在進行 "Class.getStudents().add(stu)" 這樣的操作時, 
    出現意外情況(如: stu.getClass=null,即:stu沒有所屬班級),
    即“添加方”(Student)與“被添加方”(Class),存在“外鍵”不一致的情況發生。 
    所以就出現了 那條多余的update語句。即:one-to-many(Class端)主動去維護Child.Class_id 
    所以就是說,Hibernate怕出錯,就給你多執行一次無用的更新語句,以保證 add 到 Class“集合”中的所有Student
    都是要與Class有外鍵關聯的。

    用普通話說就是:
    一年1班.getStudents().add(小白兔);
    一年1班.getStudents().add(大白兔);

    也就是說現在不管是 小白兔 還是 大白兔 
    如果他們,目前還沒有自己的班級的話,
    一年1班的班主任就會主動邀請他們成為一年1班的同學啦~。

    也就是說 一年1班的班主任 主動邀請 同學,而不是 同學自己來~~~ 所以效率也降低了。。。。

    所以我們一般把 一對多端 invser設置為true,即:不讓主控端去維護主鍵關聯,
    (即:讓同學自己去找班級)
    說白了,就是,one-to-many端不用去管理 “新添加對象” 的主外鍵約束問題。

    把one-to-many端(即:class端)的invser設置為true
    (即:每次向class.getStudents這個集合中添加 student時,不去主動update對應的外鍵),
    而是在student端去手動設置
    例如:
    student.setClass(class);
    session.save(student);
    這樣手動設置 student與class關聯啦。。。。
    所以上面的程序“最好”還是寫成這樣:

    Class class = new Class();
    class.setName("一年級1班");
    session.save(class);

    Student stu = new Student();
    stu.setName("小白兔");
    stu.setClass(class);
    session.save(class);

    /*
    此時向class集合add內容,不會進行數據庫操作(update)。
    “更新”的只是session緩存中,數據鏡像。
    這樣做的好處是:不僅減少了update語句,
    而且,同時也更新了session緩存。
    ------------------------
    而在原來:
    one-to-many端inverse=false時,雖然也更新seesion緩存中的class集合,
    但是有卻又多余update
    */
    class.getStudents().add(stu);
    // 提交

    總結:
    當inverse=false 并且向one-to-many端的關聯集合,添加“新對象(即: 自由態對象)” 時,
    Hibernate就會自動,去update那“個剛剛到來的” “自由態對象”的外鍵。
    (如果你向,one-to-many端添的集合中,add一個“已經持久化了的對象”,那就不會出現update了(因為已經持久化過了),除非,你去 更改“那個持久化對象”所對應的外鍵。。。那樣的話。。。呵呵呵~~~
    你可以試一試,應該不會報錯,你可以當做練習去做一下,加深cascade和inverse這兩個屬性的理解)


    // 如果看懂了上面的內容。來看一下,下面的東西。
    假如,將one-to-many端(即:Class端)的 hbm.xml 文檔中的cascade移除掉 或把cascade="none"。
    那么上面的代碼會出現什么情況呢。
    結果會出現2條HQL,和一堆Exception

    insert into demo.class (cid, cname) values (66666666666666666666666666666666, 一年級1班)
    update demo.student set class_id=66666666666666666666666666666666 where sid=8888888888888888811cb2e04c888888
    Hibernate Exceptinon......................................

    相比較cascade被設置"save-update"的時候,缺少了1條 insert語句,而且也多了一些Exception。

    那么,到底是少了哪1條insert語句呢?
    就是這條:
    insert into demo.student (sid,sname,class_id) values (8888888888888888811cb2e04c888888, 小白兔, 66666666666666666666666666666666)

    之所以會出現,這樣的現象,想必您已經早就看出來了。
    因為,我沒有設置Class端的Cascade,所以在save(class)的時候,并沒有自動將其所關聯的“自由態對象”進行持久化操作。
    然而,又因為 Class端的inverse=false,所以,Class會自動去維持,那個 “新來的student” 的外鍵。
    所以會出現,沒有insert就要update啦。。。。
    然后在就是Exception了

    主站蜘蛛池模板: 免费播放一区二区三区| 久久久婷婷五月亚洲97号色| 4444www免费看| 免费精品国产自产拍在线观看| 亚洲成a人片在线观看中文app| 亚洲午夜无码久久久久| 国产精品另类激情久久久免费 | 一本色道久久88亚洲综合| 99在线精品视频观看免费| a级毛片100部免费观看| 特级毛片aaaa免费观看| 亚洲人成色777777精品| 亚洲一卡二卡三卡四卡无卡麻豆 | 久久美女网站免费| 在线免费视频你懂的| 香蕉视频免费在线播放| 亚洲aⅴ无码专区在线观看春色| 亚洲人成7777影视在线观看| 亚洲欧洲免费视频| 亚洲AV无码乱码国产麻豆穿越| 中文字幕不卡亚洲| 久久精品国产精品亚洲人人| 亚洲国产V高清在线观看| 国产精品免费视频一区| 午夜视频在线观看免费完整版 | 亚洲欧美日韩一区二区三区| 亚洲一区二区三区国产精品无码| 亚洲国产综合专区电影在线 | 久久久久久成人毛片免费看 | 国产AV无码专区亚洲Av| 中文字幕亚洲激情| 成人午夜亚洲精品无码网站| 久久久久亚洲AV无码专区网站| 久久国产成人精品国产成人亚洲| 亚洲综合精品网站在线观看| 国产亚洲成人在线播放va| 中文字幕亚洲不卡在线亚瑟| 亚洲欧洲成人精品香蕉网| 亚洲日韩国产精品第一页一区| 久久久久久久尹人综合网亚洲| 亚洲日产韩国一二三四区|