溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Hibernate與對象是怎么共事的

發(fā)布時間:2021-12-04 16:27:42 來源:億速云 閱讀:139 作者:iii 欄目:編程語言

本篇內(nèi)容介紹了“Hibernate與對象是怎么共事的”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

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

也就是說,相對于常見的JDBC/SQL持久層方案中需要管理SQL語句,Hibernate采用了更自然的面向?qū)ο蟮囊暯莵沓志没疛ava應用中的數(shù)據(jù)。

換句話說,使用Hibernate的開發(fā)者應該總是關注對象的狀態(tài)(state),不必考慮SQL語句的執(zhí)行。這部分細節(jié)已經(jīng)由Hibernate掌管妥當,只有開發(fā)者在進行系統(tǒng)性能調(diào)優(yōu)的時候才需要進行了解。

1. Hibernate對象狀態(tài)(object states)

Hibernate定義并支持下列對象狀態(tài)(state):

瞬時(Transient) - 由new操作符創(chuàng)建,且尚未與Hibernate Session 關聯(lián)的對象被認定為瞬時(Transient)的。瞬時(Transient)對象不會被持久化到數(shù)據(jù)庫中,也不會被賦予持久化標識(identifier)。如果程序中沒有保持對瞬時(Transient)對象的引用,它會被垃圾回收器(garbage collector)銷毀。使用Hibernate Session可以將其變?yōu)槌志?Persistent)狀態(tài)。(Hibernate會自動執(zhí)行必要的SQL語句)

持久(Persistent) - 持久(Persistent)的實例在數(shù)據(jù)庫中有對應的記錄,并擁有一個持久化標識(identifier)。 持久(Persistent)的實例可能是剛被保存的,或剛被加載的,無論哪一種,按定義對象都僅在相關聯(lián)的Session生命周期內(nèi)的保持這種狀態(tài)。

Hibernate會檢測到處于持久(Persistent)狀態(tài)的對象的任何改動,在當前操作單元(unit of work)執(zhí)行完畢時將對象數(shù)據(jù)(state)與數(shù)據(jù)庫同步(synchronize)。開發(fā)者不需要手動執(zhí)行UPDATE。將對象從持久(Persistent)狀態(tài)變成瞬時(Transient)狀態(tài)同樣也不需要手動執(zhí)行DELETE語句。

脫管(Detached) 與持久(Persistent)對象關聯(lián)的Session被關閉后,對象就變?yōu)槊摴?Detached)的。對脫管(Detached)對象的引用依然有效,對象可繼續(xù)被修改。脫管(Detached)對象如果重新關聯(lián)到某個新的Session上, 會再次轉(zhuǎn)變?yōu)槌志?Persistent)的(Detached其間的改動將被持久化到數(shù)據(jù)庫)。

這個功能使得一種編程模型,即中間會給用戶思考時間(user think-time)的長時間運行的操作單元(unit of work)的編程模型成為可能。 我們稱之為應用程序事務,即從用戶觀點看是一個操作單元(unit of work)。

接下來我們來細致的討論下狀態(tài)(states)及狀態(tài)間的轉(zhuǎn)換(state transitions)(以及觸發(fā)狀態(tài)轉(zhuǎn)換的Hibernate方法)。

2. 使對象持久化

Hibernate認為持久化類(persistent class)新實例化的對象是瞬時(Transient)的。我們可將瞬時(Transient)對象與session關聯(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的持久化標識(identifier)是generated類型的,那么該標識(identifier)會自動在save()被調(diào)用時產(chǎn)生并分配給cat。如果Cat的持久化標識(identifier)是assigned類型的,或是一個復合主鍵(composite key),那么該標識(identifier)應當在調(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) );

如果你持久化的對象有關聯(lián)的對象(associated objects)(例如上例中的kittens集合)那么對這些對象(譯注:pk和kittens)進行持久化的順序是任意的(也就是說可以先對kittens進行持久化也可以先對pk進行持久化),除非你在外鍵列上有NOT NULL約束。 Hibernate不會違反外鍵約束,但是如果你用錯誤的順序持久化對象(譯注:在pk持久之前持久kitten),那么可能會違反NOT NULL約束。

通常你不會為這些細節(jié)煩心,因為你很可能會使用Hibernate的傳播性持久化(transitive persistence)功能自動保存相關聯(lián)那些對象。 這樣連違反NOT NULL約束情況都不會出現(xiàn)了Hibernate會管好所有的事情。傳播性持久化(transitive persistence)將在本章稍后討論。

3. 裝載對象

如果你知道某個實例的持久化標識(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()方法可能拋出無法恢復的異常(unrecoverable exception)。 如果類的映射使用了代理(proxy),load()方法會返回一個未初始化的代理,直到你調(diào)用該代理的某方法時才會去訪問數(shù)據(jù)庫。 若你希望在某對象中創(chuàng)建一個指向另一個對象的關聯(lián),又不想在從數(shù)據(jù)庫中裝載該對象時同時裝載相關聯(lián)的那個對象,那么這種操作方式就用得上的了。 如果為相應類映射關系設置了batch-size, 那么使用這種操作方式允許多個對象被一批裝載(因為返回的是代理,無需從數(shù)據(jù)庫中抓取所有對象的數(shù)據(jù))。

如果你不確定是否有匹配的行存在,應該使用get()方法,它會立刻訪問數(shù)據(jù)庫,如果沒有對應的行,會返回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);

注意,任何關聯(lián)的對象或者包含的集合都不會被以FOR UPDATE方式返回, 除非你指定了lock或者all作為關聯(lián)(association)的級聯(lián)風格(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)

“Hibernate與對象是怎么共事的”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI