1. 程式人生 > >持久化物件具有自動更新資料庫能力

持久化物件具有自動更新資料庫能力

持久化物件能更新資料庫是因為它依賴了hibernate的一級快取區域的,在Hibernate中有三級快取,其中Hibernate中的一級快取,也就是Session級別的快取。hibernate向一級快取放入資料時,同時儲存快照資料,當修改一級快取的時候,在flush操作時,對比快取和快照,如果不一致,自動更新。 當commit時,會判斷快取中的資料與快照區域的資料是否一樣,如果不一樣,會發生update語句進行修改

我們已經知道,通過new新建立一個持久化例項時,該例項處於瞬態,為了讓瞬態物件轉換為持久化狀態,Hibernate Session提供了兩個方法:

Serializable save(Object obj)    將obj物件轉變為持久化狀態,該物件的屬性將被儲存到資料庫 void persist(Object obj)    將obj物件轉變為持久化狀態,該物件的屬性將被儲存到資料庫 因此為了將一個處於瞬態的物件變成持久化狀態,可以看如下程式碼片段: News n=new News(); n.setTitle("知無涯者:拉馬努金"); n.setContent("Xxxxxxxxxxxxxx"); session.save(n); 當我們將一個瞬態例項變成持久化狀態時,Hibernate會在底層對應地生成一條insert語句,這條語句負責把該例項對應的資料插入資料表。 ① 如果News的標識屬性是generated,也就是說指定了主鍵生成器,那麼Hibernate將會在執行save方法時自動生成標識屬性值,並將該標識屬性值分配給該News物件。

② 如果News的標識屬性是assigned型別的,或者是聯合主鍵,那麼該標識屬性值應當在呼叫save之前手動賦給News物件。

注意:

Hibernate之所以提供與save( )功能幾乎完全類似的persist( )方法,一方面是為了照顧JPA的用法習慣。另一方面save和persist還有一個區別:使用save( )方法儲存持久化物件時,該方法返回該持久化物件的標識屬性值即對應記錄的主鍵值;但persist( )方法儲存持久化物件時,沒有任何返回值。因為save方法需要立即返回持久化物件的標識屬性值,所以程式執行save( )方法時會立即將持久化物件對應的資料插入資料庫。而persist方法則保證當它在一個事物外部被呼叫時,並不立即轉換成insert語句,這個功能是很有用的,尤其當我們封裝一個長會話流程的時候,persist就顯得尤為重要了。 load( )與get( ): 也可以通過load( )來載入一個持久化例項,這種載入就是根據持久化類的標識屬性值載入持久化例項------其實質就是根據主鍵從資料表中載入一條新記錄。News n=session.load(News.class,new Integer(pk));pk就是需要載入的持久化例項的標識屬性。 如果沒有匹配的資料庫記錄,load( )方法可能丟擲HibernateException異常;如果我們在類對映檔案中指定了延遲載入,則load( )方法會返回一個未初始化的代理物件,這個代理物件並沒有裝載資料記錄,知道程式呼叫該代理物件的某方法時,Hibernate才會去訪問資料庫。 如果希望在某物件中建立一個指向另一個物件的關聯,又不想在從資料庫中裝載該物件的同時裝載相關聯的所有物件,這種延遲載入的方式就非常有用了。 與load( )方法類似的是get( )方法,get( )方法也用於根據主鍵裝載持久化例項,但get( )方法會立刻訪問資料庫,如果沒有對應的記錄,get( )方法返回null,而不是返回一個代理物件。 一旦載入了該持久化例項後,該實體就處於持久化狀態,在程式碼中對持久化例項所做的修改,例如:n.setTitle("新標題");這種修改將被儲存到資料庫,對標題的修改被對映成修改資料表的特定行的特定列。 程式對持久化例項所做的修改會在Session flush之後被自動儲存到資料庫,無需程式呼叫其他方法(不需要呼叫update方法)來將修改持久化。也就是說,修改物件最簡單的方法就是在Session處於開啟狀態時load,或get它,然後直接修改即可。

對於一個曾經持久化過的、但現在已脫離Session管理的持久化物件,我們把它稱為處於脫管狀態。當我們修改脫管物件的狀態後,程式應該使用新的Session來儲存這些修改。Hibernate提供了update( )、merge( )和updateOrSave( )等方法來儲存這些修改。

News n=firstSession.load(News.class,new Integer(pk)); firstSession.close(); n.setTitle("新標題"); Session secondSession=HibernateSessionFactory.getSession(); secondSession.update(n); 當我們用另一個Session來儲存這種修改後,該脫管物件再次回到Session的管理之下,也就再次回到持久化狀態。 當需要使用update( )來儲存程式對持久化物件所做的修改時,如果不清楚該物件是否曾經持久化過,那麼程式可以選擇使用updateOrSave( )方法,該方法自動判斷該物件是否曾經持久化,如果曾經持久化過,就使用update方法,否則將使用save操作。

merge( )方法也可將程式對脫管物件所做的修改儲存到資料庫,但merge方法與update方法最大的區別就是:merge( )方法不會持久化給定物件。舉例來說,當我們執行session.update(a)程式碼後,a物件將會變成持久化狀態;而執行session.merge(a)程式碼後,a物件依然不是持久化狀態,a物件依然不會被關聯到Session上。 --------------------- 

在hibernate中,持久化物件分為三種狀態: 1)瞬時態 transient  (臨時物件) :無持久化標識OID,未與Session關聯 , 2)持久態 persistent  :存在持久化標識OID,與Session關聯 3)脫管態 detached (離線物件):存在持久化標識OID,未與Session關聯 (session.close)

物件的狀態可以相互之間進行轉換 直接獲得瞬時態物件:new Customer() 瞬時 --》持久 session.save(customer); 瞬時 --》託管 customer.setId(1);

直接獲得持久態物件:session.get(); 持久 --》瞬時 session.delete(); 持久 --》託管 sesion.evict,session.close,session.clear,清除物件在一級快取中的引用

直接獲得託管物件:不能直接獲得 託管 --》瞬時 刪除OID 託管 --》持久 update ,saveOrUpdate

而只要session存在,它的快取的生命週期就一直存在。Session flush的三種情況為事務提交、呼叫查詢方法(query)以及手動呼叫flush,session.close()。

持久化物件在一級快取中的值改變後,與所對應的快照區的資料不同,每當觸發Session flush後,會主動更新資料庫,例如:

    @Test     public void test123() {         Session session =sessionFactory.getCurrentSession();         Transaction tx = session.beginTransaction();         //c持久態------存在於session的快取中         Customer c1 = (Customer) session.get(Customer.class, 1);                  //改變持久態物件         c1.setName("rose");                  Query query = session.createQuery("from Customer");         //list查詢時會flush         query.list();                  //事務提交時會flush         tx.commit();         session.close();           // 因為session已經關閉,託管態物件         System.out.println(c1.getId());     } 在上述方法中,當程式執行到query.list()時,會自動更物件c1,,而在事務提交以及session關閉時,持久化物件c1的值與快照區的值相同,故不會執行update。此方法中的update執行在兩個select之間。 ---------------------  作者:記錄點滴人生  來源:CSDN  原文:https://blog.csdn.net/wodatoucai/article/details/17427005  版權宣告:本文為博主原創文章,轉載請附上博文連結!

作者:confirmAname  來源:CSDN  原文:https://blog.csdn.net/confirmaname/article/details/9290535  版權宣告:本文為博主原創文章,轉載請附上博文連結!