新聞中心
Hibernate與對象是如何共事的呢?Hibernate是完整的對象/關(guān)系映射解決方案,它提供了對象狀態(tài)管理(state management)的功能,使開發(fā)者不再需要理會底層數(shù)據(jù)庫系統(tǒng)的細節(jié)。

也就是說,相對于常見的JDBC/SQL持久層方案中需要管理SQL語句,Hibernate采用了更自然的面向?qū)ο蟮囊暯莵沓志没疛ava應(yīng)用中的數(shù)據(jù)。
換句話說,使用Hibernate的開發(fā)者應(yīng)該總是關(guān)注對象的狀態(tài)(state),不必考慮SQL語句的執(zhí)行。這部分細節(jié)已經(jīng)由Hibernate掌管妥當(dāng),只有開發(fā)者在進行系統(tǒng)性能調(diào)優(yōu)的時候才需要進行了解。
1. Hibernate對象狀態(tài)(object states)
Hibernate定義并支持下列對象狀態(tài)(state):
瞬時(Transient) - 由new操作符創(chuàng)建,且尚未與Hibernate Session 關(guān)聯(lián)的對象被認(rèn)定為瞬時(Transient)的。瞬時(Transient)對象不會被持久化到數(shù)據(jù)庫中,也不會被賦予持久化標(biāo)識(identifier)。如果程序中沒有保持對瞬時(Transient)對象的引用,它會被垃圾回收器(garbage collector)銷毀。使用Hibernate Session可以將其變?yōu)槌志?Persistent)狀態(tài)。(Hibernate會自動執(zhí)行必要的SQL語句)
持久(Persistent) - 持久(Persistent)的實例在數(shù)據(jù)庫中有對應(yīng)的記錄,并擁有一個持久化標(biāo)識(identifier)。 持久(Persistent)的實例可能是剛被保存的,或剛被加載的,無論哪一種,按定義對象都僅在相關(guān)聯(lián)的Session生命周期內(nèi)的保持這種狀態(tài)。
Hibernate會檢測到處于持久(Persistent)狀態(tài)的對象的任何改動,在當(dāng)前操作單元(unit of work)執(zhí)行完畢時將對象數(shù)據(jù)(state)與數(shù)據(jù)庫同步(synchronize)。開發(fā)者不需要手動執(zhí)行UPDATE。將對象從持久(Persistent)狀態(tài)變成瞬時(Transient)狀態(tài)同樣也不需要手動執(zhí)行DELETE語句。
脫管(Detached) 與持久(Persistent)對象關(guān)聯(lián)的Session被關(guān)閉后,對象就變?yōu)槊摴?Detached)的。對脫管(Detached)對象的引用依然有效,對象可繼續(xù)被修改。脫管(Detached)對象如果重新關(guān)聯(lián)到某個新的Session上, 會再次轉(zhuǎn)變?yōu)槌志?Persistent)的(Detached其間的改動將被持久化到數(shù)據(jù)庫)。
這個功能使得一種編程模型,即中間會給用戶思考時間(user think-time)的長時間運行的操作單元(unit of work)的編程模型成為可能。 我們稱之為應(yīng)用程序事務(wù),即從用戶觀點看是一個操作單元(unit of work)。
接下來我們來細致的討論下狀態(tài)(states)及狀態(tài)間的轉(zhuǎn)換(state transitions)(以及觸發(fā)狀態(tài)轉(zhuǎn)換的Hibernate方法)。
2. 使對象持久化
Hibernate認(rèn)為持久化類(persistent class)新實例化的對象是瞬時(Transient)的。我們可將瞬時(Transient)對象與session關(guān)聯(lián)而變?yōu)槌志?Persistent)的。
- DomesticCat fritz = new DomesticCat();
- fritz.setColor(Color.GINGER);
- fritz.setSex('M');
- fritz.setName("Fritz");
- Long generatedId = (Long) sess.save(fritz);
如果Cat的持久化標(biāo)識(identifier)是generated類型的,那么該標(biāo)識(identifier)會自動在save()被調(diào)用時產(chǎn)生并分配給cat。如果Cat的持久化標(biāo)識(identifier)是assigned類型的,或是一個復(fù)合主鍵(composite key),那么該標(biāo)識(identifier)應(yīng)當(dāng)在調(diào)用save()之前手動賦予給cat。 你也可以按照EJB3 early draft中定義的語義,使用persist()替代save()。
此外,你可以用一個重載版本的save()方法。
- DomesticCat pk = new DomesticCat();
- pk.setColor(Color.TABBY);
- pk.setSex('F');
- pk.setName("PK");
- pk.setKittens( new HashSet() );
- pk.addKitten(fritz);
- sess.save( pk, new Long(1234) );
如果你持久化的對象有關(guān)聯(lián)的對象(associated objects)(例如上例中的kittens集合)那么對這些對象(譯注:pk和kittens)進行持久化的順序是任意的(也就是說可以先對kittens進行持久化也可以先對pk進行持久化),除非你在外鍵列上有NOT NULL約束。 Hibernate不會違反外鍵約束,但是如果你用錯誤的順序持久化對象(譯注:在pk持久之前持久kitten),那么可能會違反NOT NULL約束。
通常你不會為這些細節(jié)煩心,因為你很可能會使用Hibernate的傳播性持久化(transitive persistence)功能自動保存相關(guān)聯(lián)那些對象。 這樣連違反NOT NULL約束情況都不會出現(xiàn)了Hibernate會管好所有的事情。傳播性持久化(transitive persistence)將在本章稍后討論。
3. 裝載對象
如果你知道某個實例的持久化標(biāo)識(identifier),你就可以使用Session的load()方法 來獲取它。 load()的另一個參數(shù)是指定類的.class對象。 本方法會創(chuàng)建指定類的持久化實例,并從數(shù)據(jù)庫加載其數(shù)據(jù)(state)。
- Cat fritz = (Cat) sess.load(Cat.class, generatedId);
- // you need to wrap primitive identifiers
- long pkId = 1234;
- DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );
此外, 你可以把數(shù)據(jù)(state)加載到指定的對象實例上(覆蓋掉該實例原來的數(shù)據(jù))。
- Cat cat = new DomesticCat();
- // load pk's state into cat
- sess.load( cat, new Long(pkId) );
- Set kittens = cat.getKittens();
請注意如果沒有匹配的數(shù)據(jù)庫記錄,load()方法可能拋出無法恢復(fù)的異常(unrecoverable exception)。 如果類的映射使用了代理(proxy),load()方法會返回一個未初始化的代理,直到你調(diào)用該代理的某方法時才會去訪問數(shù)據(jù)庫。 若你希望在某對象中創(chuàng)建一個指向另一個對象的關(guān)聯(lián),又不想在從數(shù)據(jù)庫中裝載該對象時同時裝載相關(guān)聯(lián)的那個對象,那么這種操作方式就用得上的了。 如果為相應(yīng)類映射關(guān)系設(shè)置了batch-size, 那么使用這種操作方式允許多個對象被一批裝載(因為返回的是代理,無需從數(shù)據(jù)庫中抓取所有對象的數(shù)據(jù))。
如果你不確定是否有匹配的行存在,應(yīng)該使用get()方法,它會立刻訪問數(shù)據(jù)庫,如果沒有對應(yīng)的行,會返回null。
- Cat cat = (Cat) sess.get(Cat.class, id);
- if (cat==null) {
- cat = new Cat();
- sess.save(cat, id);
- }
- return cat;
你甚至可以選用某個LockMode,用SQL的SELECT ... FOR UPDATE裝載對象。 請查閱API文檔以獲取更多信息。
- Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);
注意,任何關(guān)聯(lián)的對象或者包含的集合都不會被以FOR UPDATE方式返回, 除非你指定了lock或者all作為關(guān)聯(lián)(association)的級聯(lián)風(fēng)格(cascade style)。
任何時候都可以使用refresh()方法強迫裝載對象和它的集合。如果你使用數(shù)據(jù)庫觸發(fā)器功能來處理對象的某些屬性,這個方法就很有用了。
- sess.save(cat);
- sess.flush(); //force the SQL INSERT
- sess.refresh(cat); //re-read the state (after the trigger executes)
此處通常會出現(xiàn)一個重要問題: Hibernate會從數(shù)據(jù)庫中裝載多少東西?會執(zhí)行多少條相應(yīng)的SQLSELECT語句? 這取決于抓取策略(fetching strategy),這里我們不再做以解釋。
網(wǎng)頁標(biāo)題:初步了解Hibernate與對象共事
文章轉(zhuǎn)載:http://www.5511xx.com/article/dhdhhed.html


咨詢
建站咨詢
