新聞中心
關(guān)于Hibernate中 cascade 與 inverse 的理解。

成都創(chuàng)新互聯(lián)公司服務項目包括金山網(wǎng)站建設、金山網(wǎng)站制作、金山網(wǎng)頁制作以及金山網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,金山網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到金山省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!
您買的Hibernate書是哪一本呢? 孫衛(wèi)琴的精通Hibernate,還是 深入淺出Hibernate還是那本。。。
我是兩本都買了,總體來說還可以,但是,有的地方講的比較書面化,比如inverse這屬性。
在學習Hibernate的過程中最不好理解的就是這兩個屬性了。
(我當初學習Hibernate的時候,發(fā)現(xiàn)網(wǎng)上介紹這兩個屬性的文章倒是不少,但是,居然有好多都是轉(zhuǎn)帖。。。還有的就是 照書搬~~-_-!!!)。。。
據(jù)個例子:書上說inverse=false時,由主控方維持關(guān)系。。。
由于我也是初學者。。。再加上語文水平偏低。。。不理解“維持關(guān)系是啥意思”囧~
提示:
(1)如果:您不了解Hibernate的one-to-many或many-to-one的概念。
(2)如果:你不了解Hibernate的“自由態(tài)”“持久態(tài)”“游離態(tài)”的概念。
(3)如果:您不了解Hibernate中的“臟數(shù)據(jù)”的概念。
(4)如果:您對Hibernate中Session緩存,沒有初步了解的話。
(在Hibernate中調(diào)用save進行存儲數(shù)據(jù)的時候,并不是馬上就對數(shù)據(jù)庫進行insert操作,而是會將其“數(shù)據(jù)對象(vo)”納入Hibernate的Session緩存。)
在上面的4條提示中,如果您對其中的某一條,不是很清楚的話。希望請先了解有關(guān)知識。
否則,可能您將 “無法或很難”理解 cascade 或 inverse 這2個屬性。
首相,cascade 與 inverse 這兩個屬性,其實是完全不同的兩個東西,想要了解他們各自的“用途與區(qū)別”,詳見如下介紹:
這里有兩個表:
(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--------
- catalog="demo">
- "cid" type="java.lang.String">
- "cid" length="32" />
- class="uuid.hex" />
- "name" type="java.lang.String">
- "cname" length="16" not-null="true" />
- "students" table="student" cascade="save-update">
- "class" />
- class="lcx.vo.Student" />
- class>
- //--------Student類的代碼;*******
- public class Student implements.....
- {
- private sId = "";
- private sName = "";
- private Class class = null;
- // 省略對應的 geter setter
- }
- // Student.hbm.xml
- "cid" type="java.lang.String">
- "sid" length="32" />
- class="uuid.hex" />
- "class"
- class="lcx.vo.Class"
- column="class_id"
- not-null="true"
- />
- class>
(一) cascade 的介紹:
當Hibernate持久化一個“臨時對象(也叫自由態(tài)對象)”時,在默認的情況下(即:沒有設置cascade屬性或cascade=none時),Hibernate不會自動“持久化他所關(guān)聯(lián)”的其他臨時對象。
上面這些話是什么意思呢? 什么叫不會自動 “持久化”關(guān)聯(lián)的臨時對象呢?
看如下代碼:
- // 創(chuàng)建一個 臨時對象(也叫自由態(tài)對象)
- // 也就是說這個 class 沒有被Hibernate納入Session緩存管理。
- Class class = new Class();
- //class.id 為自動生成
- class.setName("一年級1班");
- Student stu = new Student();
- //student.id 為自動生成
- stu.setName("小白兔");
- stu.setClass(class);
- // 關(guān)鍵就是這里。。。
- 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
- //----------------------------------------********
那么為什么會出現(xiàn),這3條HQL語句呢,我們來一一分析一下:
第1條HQL語句:
其實第一條HQL比較好理解,
當我們調(diào)用 session.save(class) 后,在Hibernate進行提交的時候,
會發(fā)現(xiàn)“有”一條“新”的數(shù)據(jù)要插入(insert),所以就往class表中,插入了這條新的class記錄。
第2條HQL語句:
注意問題就在這里:
這里為什么又出現(xiàn)了一條insert語句呢?而且還是向student表中插入數(shù)據(jù)。
我們在上面的代碼中,并沒有編寫類似“session.save(student)”這樣的語句啊。
這是為什么呢?
其實原因,是這么回事:因為我們在class端,設置了"級聯(lián)更新"(即:cascade="save-update"),
也就是說,當Hibernate在向class表中插入“新”對象記錄時,會檢查“Class對象”所關(guān)聯(lián)的屬性(就是 對應的屬性),是否發(fā)生過變化,如果發(fā)生了變化,就按照“級聯(lián)屬性(cascade)”所設定的內(nèi)容
進行操作。
上面講的這句話到底是什么意思呢?
用你們“人”話說,就是:
因為調(diào)用了 class.getStudents().add(stu);
所以,在Hibernate在進行插入 class對象的時候,發(fā)現(xiàn)class對象,所關(guān)聯(lián)的集合中,有一條
“自由態(tài)”的對象,而又因為class端設置了“級聯(lián)屬性cascade”,所以,在插入這條 “新class對象”時,也一同把他內(nèi)部的那些,還屬于“自由態(tài)”的其他對象,也一同插入到,他們所對應的表中去了。
還是不明白的話。。??梢钥纯础O衛(wèi)琴的《精通Hibernate》,在書上的第149頁有。
但是關(guān)于inverse的介紹。。。寫的就有些書面化了,如果語文不好的話。。。就難懂咯~
第3條HQL語句:
第三條HQL語句是一條update語句,是不是覺得,很莫名其妙。。。。
Hibernate大腦進水了吧,怎么吃飽了撐得,重復更新記錄啊啊啊啊啊
假如:我們把 class端的配置文檔中的 invser屬性設置為true(即:inverse=true)
在執(zhí)行上面的程序,發(fā)現(xiàn),就變成2條insert語句啦。。。。。(update沒啦。。。)
看來第三條的update語句和inverse有著密切的關(guān)系(他兩有一腿~)。
所以我們下邊,就來介紹一下inverse屬性:
當調(diào)用 Class.getStudents().add(stu)方法,進行添加操作時,
(即:向 "這個Class對象"所屬的“集合 (也就是調(diào)用getStudents方法所返回的那個Set集合)”中添加一個Student(即 add(stu)),也就是說,這個“新”添加的Student對象(stu),
他的Student.class_id字段“必須”,要等于“被添加方Class”的主鍵(即:Class.cid)。
從“數(shù)據(jù)庫”層面來講,也就是說,這個“新”添加的“Student”的class_id字段,必須要與“Class”的cid字段,存在"主外鍵關(guān)聯(lián)"。)
正因為如此:所以Hibernate“怕” 在進行 "Class.getStudents().add(stu)" 這樣的操作時,
出現(xiàn)意外情況(如: stu.getClass=null,即:stu沒有所屬班級),
即“添加方”(Student)與“被添加方”(Class),存在“外鍵”不一致的情況發(fā)生。
所以就出現(xiàn)了 那條多余的update語句。即:one-to-many(Class端)主動去維護Child.Class_id
所以就是說,Hibernate怕出錯,就給你多執(zhí)行一次無用的更新語句,以保證 add 到 Class“集合”中的所有Student
都是要與Class有外鍵關(guān)聯(lián)的。
用普通話說就是:
一年1班.getStudents().add(小白兔);
一年1班.getStudents().add(大白兔);
也就是說現(xiàn)在不管是 小白兔 還是 大白兔
如果他們,目前還沒有自己的班級的話,
一年1班的班主任就會主動邀請他們成為一年1班的同學啦~。
也就是說 一年1班的班主任 主動邀請 同學,而不是 同學自己來~~~ 所以效率也降低了。。。。
所以我們一般把 一對多端 invser設置為true,即:不讓主控端去維護主鍵關(guān)聯(lián),
(即:讓同學自己去找班級)
說白了,就是,one-to-many端不用去管理 “新添加對象” 的主外鍵約束問題。
把one-to-many端(即:class端)的invser設置為true
(即:每次向class.getStudents這個集合中添加 student時,不去主動update對應的外鍵),
而是在student端去手動設置
例如:
- student.setClass(class);
- session.save(student);
- 這樣手動設置 student與class關(guān)聯(lián)啦。。。。
- 所以上面的程序“最好”還是寫成這樣:
- Class class = new Class();
- class.setName("一年級1班");
- session.save(class);
- Student stu = new Student();
- stu.setName("小白兔");
- stu.setClass(class);
- session.save(class);
- /*
此時向class集合add內(nèi)容,不會進行數(shù)據(jù)庫操作(update)。
“更新”的只是session緩存中,數(shù)據(jù)鏡像。
這樣做的好處是:不僅減少了update語句,
而且,同時也更新了session緩存。
------------------------
而在原來:
one-to-many端inverse=false時,雖然也更新seesion緩存中的class集合,
但是有卻又多余update
- */
- class.getStudents().add(stu);
- // 提交
總結(jié):
當inverse=false 并且向one-to-many端的關(guān)聯(lián)集合,添加“新對象(即: 自由態(tài)對象)” 時,
Hibernate就會自動,去update那“個剛剛到來的” “自由態(tài)對象”的外鍵。
(如果你向,one-to-many端添的集合中,add一個“已經(jīng)持久化了的對象”,那就不會出現(xiàn)update了(因為已經(jīng)持久化過了),除非,你去 更改“那個持久化對象”所對應的外鍵。。。那樣的話。。。呵呵呵~~~
你可以試一試,應該不會報錯,你可以當做練習去做一下,加深cascade和inverse這兩個屬性的理解)
// 如果看懂了上面的內(nèi)容。來看一下,下面的東西。
假如,將one-to-many端(即:Class端)的 hbm.xml 文檔中的cascade移除掉 或把cascade="none"。
那么上面的代碼會出現(xiàn)什么情況呢。
結(jié)果會出現(xiàn)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)
之所以會出現(xiàn),這樣的現(xiàn)象,想必您已經(jīng)早就看出來了。
因為,我沒有設置Class端的Cascade,所以在save(class)的時候,并沒有自動將其所關(guān)聯(lián)的“自由態(tài)對象”進行持久化操作。
然而,又因為 Class端的inverse=false,所以,Class會自動去維持,那個 “新來的student” 的外鍵。
所以會出現(xiàn),沒有insert就要update啦。。。。
然后在就是Exception了
【編輯推薦】
- Hibernate批量更新與刪除實例淺析
- 簡述Hibernate Synchronizer學習筆記
- Hibernate column屬性簡介
- 概括Hibernate查詢語言
- Hibernate cartridge學習總結(jié)
網(wǎng)頁標題:Hibernate中cascade與inverse屬性詳解
分享路徑:http://www.5511xx.com/article/dpiogji.html


咨詢
建站咨詢
