Hibernate向我們提供的主要的操縱資料庫的介面,Session就是其中的一個,它提供了基本的增,刪,改,查方法.而且具有一個緩衝機制,能夠按照某個時間點,按照緩衝中的持久化對象屬性的變化來更新資料庫,著就是Session的緩衝清理過程.在Hibernate中對象分為三個狀態,臨時,持久化,游離.如果我們希望JAVA裡的一個對象一直存在,就必須有一個變數一直引用著這個對象.當這個變數沒了.對象也就被JVM回收了.這篇部落格我們就帶大家一起來看一下session的緩衝機制,也就是hibernate的一級緩衝,還有hibernate三種對象狀態的詳細情況。
當Session的save()方法持久化一個Customer對象時,Customer對象被加入到Session的緩衝中,以後即使應用程式中的引用變數不再引用Customer對象,只要Session的緩衝還沒有被清空,Customer對象仍然處於生命週期中。 當Session的load()方法試圖從資料庫中載入一個Customer對象時,Session先判斷緩衝中是否已經存在這個Customer對象,如果存在,就不需要再到資料庫中檢索。 這樣就大大提高了hibernate查詢的時間效率,只有當事務提交,session關閉之後,session緩衝才會失效
下面我們來通過一段代碼來理解一下session緩衝:
tx = session.beginTransaction(); Customer c1=new Customer(“zhangsan",new HashSet()); //Customer對象被持久化,並且加入到Session的緩衝中 session.save(c1); Long id=c1.getId(); //c1變數不再引用Customer對象 c1=null; //從Session緩衝中讀取Customer對象,使c2變數引用Customer對象 Customer c2=(Customer)session.load(Customer.class,id); tx.commit(); //關閉Session,清空緩衝 session.close(); //訪問Customer對象 System.out.println(c2.getName()); // c2變數不再引用Customer對象,此時Customer對象結束生命週期。 c2=null;
當session調用save儲存一個對象時,這個對象就被載入到session緩衝當中,其實調用save方法這裡有個細節,很多人都忽略了這個細節,就是save方法有一個傳回值,返回一個seriaseble介面類型的資料,我們知道像基礎資料型別 (Elementary Data Type)的封裝類型都實現了這個介面,其實這個傳回值我們可以理解為儲存對象的id,我們在很多時候都能用到這個傳回值,這是一個應該注意的地方。當對象被save到緩衝中時,我們就可以調用對象的getid方法來獲得他的id了。在上面的樣本中我們可以看到,雖然c1被複位null了,但是此時在session緩衝裡面還是有一個變數指向著該對象,所以該對象才不被記憶體回收行程回收,當我們在此利用該對象的id去用load查詢時,其實還是去到session緩衝去找並且返回該對象,當session關閉後。緩衝清空。
下面我們在來看一個例子,來看一下get和load的另一個不同點:
tx = session.beginTransaction(); Customer c1=(Customer)session.load(Customer.class,new Long(1)); Customer c2=(Customer)session.load(Customer.class,new Long(1)); System.out.println(c1==c2); // true or false ?? tx.commit(); session.close();
很明顯,這個樣本最後列印出來的是true,因為他們獲得的是同一個執行個體,我們具體來分析一下,我們在運行這段代碼時,細心的童鞋應該會發現,利用load去查詢對象時,沒有產生sql語句,這是為什麼呢?既然查詢到結果了,為什麼沒有產生出來sql語句呢。這就是我們要說的load和get方法的第二個不同的地方了,load方法在查詢時,其實是獲得的該對象的一個代理的對象,當我們用到查詢到的對象時,他才會去資料庫進行查詢,如上,如果我們調用c1.getName方法,這時就會列印出sql語句來,這時候他才真正的去資料庫查詢,而get方法,他在執行get的方法的時候就會去資料庫查詢,產生sql語句
Session緩衝的作用
(1)減少訪問資料庫的頻率。應用程式從記憶體中讀取持久化對象的速度顯然比到資料庫中查詢資料的速度快多了,因此Session的緩衝可以提高資料訪問的效能。
(2)保證緩衝中的對象與資料庫中的相關記錄保持同步。當緩衝中持久化對象的狀態發生了變化,Session並不會立即執行相關的SQL語句,這使得Session能夠把幾條相關的SQL語句合并為一條SQL語句,以便減少訪問資料庫的次數,從而提高應用程式的效能。
Session的清理緩衝
清理緩衝是指按照緩衝中對象的狀態的變化來同步更新資料庫,下面我們還是具體來看一段代碼:以下程式碼對Customer的name屬性修改了兩次:
tx = session.beginTransaction(); Customer customer=(Customer)session.load(Customer.class, new Long(1)); customer.setName("Jack"); customer.setName("Mike"); tx.commit();
當Session清理緩衝時,只需執行一條update語句:
update CUSTOMERS set NAME= 'Mike'…… where ID=1;
其實第一次調用setName是無意義的,完全可以省略掉。
Session緩衝在什麼時候才清理呢?我們來看一下:
Session會在下面的時間點清理緩衝:
1.當應用程式調用org.hibernate.Transaction的commit()方法的時候,commit()方法先清理緩衝,然後再向資料庫提交事務。
2.當應用程式顯式調用Session的flush()方法的時候,其實這個方法我們幾乎很少用到,因為我們一般都是在完成一個事務才去清理緩衝,提交資料更改,這樣我們直接提交事務就可以。
Hibernate中java對象的三種狀態:
1、臨時狀態(transient):剛剛用new語句建立,還沒有被持久化,不處於Session的緩衝中。處於臨時狀態的Java對象被稱為臨時對象。
2、持久化狀態(persistent):已經被持久化,加入到Session的緩衝中。處於持久化狀態的Java對象被稱為持久化對象。
3、游離狀態(detached):已經被持久化,但不再處於Session的緩衝中。處於游離狀態的Java對象被稱為游離對象。
持久化狀態和臨時狀態的不同點在於:
1、對象持久化狀態時,他已經和資料庫打交道了,在資料庫裡面存在著該對象的一條記錄。
2、持久化狀態的對象存在於session的緩衝當中。
3、持久化狀態的對象有自己的OID。
游離狀態的對象與持久化狀態的對象不同體現在游離狀態的對象已經不處於session的緩衝當中,並且在資料庫裡面已經不存在該對象的記錄,但是他依然有自己的OID。
對象的狀態轉換
我們一起來分析一下這個狀態轉換圖,首先一個對象被new出來之後,他是出於臨時狀態的,然後調用save或者saveOrUpdate方法把對象轉換為持久化狀態,這裡的saveOrUpdate方法其實是一個偷懶的方法,我們以前用的所有的save方法的地方都可以修改為該方法,這個方法是在儲存資料之前先查看一下這個對象是什麼狀態,如果是臨時狀態就儲存,如果是游離狀態就進行更新。持久化狀態轉換成游離狀態可以是在session關閉或者被清理緩衝時,在或者就是調用evict方法,這個方法就是強行把對象從session緩衝中清除。游離狀態裝換為持久化狀態可以調用update方法,其實update方法主要的功能就是把對象從游離狀態裝換成持久化狀態的,因為一般的更新其實不用這個方法也可以。
下面我們舉一個具體執行個體的看一下狀態轉換過程:
這個圖需要大家仔細的理解一下,他很好的體現了對象生命週期的進程和對象狀態的轉換。
下面我們在用一個樣本來看一下session的update方法是怎麼把一個游離狀態的對象裝換成持久化的:
Customer customer=new Customer(); customer.setName("Tom"); Session session1=sessionFactory.openSession(); Transaction tx1 = session1.beginTransaction(); session1.save(customer); tx1.commit(); session1.close(); //此時Customer對象變為游離對象 Session session2=sessionFactory.openSession(); Transaction tx2 = session2.beginTransaction(); customer.setName(“zhangsan") //在和session2關聯之前修改Customer對象的屬性 session2.update(customer); customer.setName(“lisi"); //在和session2關聯之後修改Customer對象的屬性 tx2.commit(); session2.close();
當session1儲存完對象,然後事務關閉時,對象就變為游離狀態了,此時我們在開啟一個session,利用update方法,在把對象和session關聯起來,然後修改他的屬性,提交事務之後,游離狀態的對象一樣可以修改儲存到資料庫中,這裡雖然修改了兩次對象的屬性,但只會發送一條sql語句,因為update在修改對象資料時,只有在事務提交時,他才會發送sql語句進行提交。所以只有最後一條修改資訊管用。
總結一下Session的update()方法完成以下操作:
(1)把Customer對象重新加入到Session緩衝中,使它變為持久化對象。
(2)計劃執行一個update語句。值得注意的是,Session只有在清理緩衝的時候才會執行update語句,並且在執行時才會把Customer對象當前的屬性值組裝到update語句中。因此,即使程式中多次修改了Customer對象的屬性,在清理緩衝時只會執行一次update語句。
Web應用程式客戶層和商務邏輯層之間傳遞臨時對象和有利對象的過程:
Session的二級緩衝
Hibernate提供了兩級緩衝,第一級緩衝是Session的緩衝。由於Session對象的生命週期通常對應一個資料庫事務或者一個應用事務,因此它的緩衝是事務範圍的緩衝。第一級緩衝是必須的,不允許而且事實上也無法被卸載。在第一級緩衝中,持久化類的每個執行個體都具有惟一的OID。 第二級緩衝是一個可插拔的快取區外掛程式,它由SessionFactory負責管理。由於SessionFactory對象的生命週期和應用程式的整個進程對應,因此第二級緩衝是進程範圍的緩衝。這個緩衝中存放的是對象的散裝資料。第二級緩衝是可選的,可以在每個類或每個集合的粒度上配置第二級緩衝。
Hibernate二級緩衝結構
關於hibernate二級緩衝的詳細內容我們將會在以後的部落格中詳細介紹,這裡我們只是簡單介紹一下,詳細內容敬請期待以後的文章。。。。