對象的持久化狀態:hibernate中的緩存:1)一級緩存 2)二級緩存
一級緩存:內置緩存 Session緩存 –---是必須用的!
緩存的工作的底層原理:
執行session.save(c1) 這個過程中:
Session下的save函數會把c1這個對象做一個快照(snapshot),然後它會生成SQL語句把c1這個對象插入到數據庫進行持久化,緊接着session下面的函數save會把c1的原對象扔到hibernate的一級緩存當中。
快照的含義:在save函數中通過克隆的技術反射出這個java對象並且將它存放到session下List<Map>這樣一個成員變量中!
一級緩存:在session類下又做了一個成員變量List它把插入數據庫的這個對象c1掉一個list.add(c1);把c1緩存起來!
通過代碼的模擬如下:
class Session
{
private List list = new ArrayList();
private List snapList = new ArrayList();
public void save(Object obj)
{
//首先做一個快照
Object objClone = obj.clone();
snapList.add(objClone);
//接着生成SQL語句將數據持久化到數據庫
Inser into(。。。。。);
//然後將原對象保存到一級緩存當中。
list.add(obj);
}
}
當利用Session對數據進行持久化DML操作的時候一級緩存就被啓用了!
緩存的含義:
Customer c1=new Customer(“Tom”,new HashSet());
session.save(c1);
Long id=c1.getId();
c1=null;//但垃圾回收不會回收c1這個對象,因爲它在hibernate的一級緩存當中已經不屬於JVM垃圾回收機制的管理了了。
Customer c2=(Customer)session.load(Customer.class,id);
//load方法去做數據庫的查詢操作,首先它會去一級緩存當中找id並且將這個對象查詢出來,若一級緩存沒有他纔去數據庫當中查詢,並且查詢出來的對象也會放在一級緩存當中!。
所以說一級緩存的做用就是爲了減少訪問數據庫的頻率,使內存的操作速度快
tx.commit();
session.close();
Session緩存的聲明週期是很短暫的:session.close()緩存就會失效-----這個過程叫做緩存清空:
在這個過程當中hibernate會把一級緩存當中的java對象和它記錄的這個快照之中的成員變量挨個的進行一個對比如果發生變化,它就會自動的生成Update語句將數據做個更新然後存放到數據庫當中。例如原來快照中存放的人名叫張三,執行完了session.save(c1);這條語句,緊接着又執行 c1.setName(“LiSi”);這個時候一級緩存(內存)當中的人名變成了LiSi 在清理緩存的時候,hibernate會將一級緩存 中的java成員變量和快照中對象的成員變量做個比較---把zhangsan更新爲lisi持久化到數據庫.
;
Session緩存的做用:
v 減少訪問數據庫的頻率;(內存操作的速度快)
v 保證緩存中的對象與數據庫中的相關記錄保持同步。當持久化對象的狀態發生改變,Session並不會立即執行相關的SQL語句,這使得Session可以把幾條相關的SQL合併爲一條,來減少訪問數據庫的次數。
v Session加載對象時,會爲對象做一個快照,當清理緩存時,會與這個備份進行比較,來決定做什麼樣的數據庫操作。
Session是麼時候清理緩存?
v 程序調用Transaction的commit()方法時,commit()方法先清理緩存,在提交數據庫的事務
v 程序調用session的find()或者iterate()時,如果緩存中的持久化對象的狀態發生了變化,就會先清理緩存,保證查詢結果能反映持久化對象的最新狀態
v 當應用程序顯示的調用Session的flush()方法時
Hibernate應用中java對象的狀態
v 臨時狀態(Transient):也叫瞬時狀態。new出來的對象,沒有被持久化處理,不處於Session緩存中的對象
v 持久化狀態(Persistent):已經被持久化,加入到Session的緩存中
v 遊離狀態(Detached):也叫脫管狀態。已經被持久化,但是不處在Session緩存中
例如下面的代碼:
Customer c1=new Customer(“Tom”,new HashSet());//c1---臨時狀態
session.save(c1);
Long id=c1.getId();//c1------持久化
c1=null;
Customer c2=(Customer)session.load(Customer.class,id);
//c2-----持久化(從一級緩存當中查詢出來的對象)
tx.commit();
session.close();
System.out.println(c2.getName());
//c2-----遊離狀態(session都關閉了)
c2=null;
總結:
v 從上面的程序可以看出,Session的save方法會使得Java對象的狀態轉變成持久化狀態;Session的close方法會使得Java對象的狀態轉變爲遊離狀態;
v 只要處於臨時狀態和遊離狀態的Java對象不再被任何變量引用,其就結束了其生命週期;但是處於持久化狀態對象不然,由於緩存還在引用這個對象,所以其還處於生命週期
臨時對象的特徵:
v 不處於Session緩存中(不被任何一個Session實例關聯)
v 在數據庫中沒有對應的記錄
v 進入臨時狀態的條件:
new一個Java對象,他處於臨時狀態,不和數據庫有任何記錄關聯
Session的delete方法能夠使一個持久化對象或遊離對象轉變爲臨時狀態;對於遊離對象,delete方法從數據庫中刪除與它對應的記錄;對於持久化對象,delete方法從數據庫中刪除與它對應的記錄,並把它從session緩存中刪除
持久化對象的特徵:
v 在一個Session實例的緩存中(與一個Session關聯)
v 持久化對象和數據庫中的相關記錄對應
v Session清理緩存時,會根據持久化對象的屬性變化,來同步更新數據庫
v 進入持久化狀態的條件
§ session的save方法
§ session的load和get方法返回的對象都是處於持久化狀態
§ session的find方法返回的List中存在的對象都是處於持久化狀態
§ session的update、saveOrUpdate和lock方法使得遊離對象轉換爲持久化狀態
§ 當一個持久化對象關聯一個臨時對象,在允許級聯保存的情況下,Session在清理緩存時把這個對象也轉變爲持久化狀態
遊離對象的特徵:
v 不再位於session緩存中(遊離對象不被Session關聯)
v 遊離對象是從持久化對象轉變過來的,因此在數據庫中可能還存在與其對應的記錄
v 遊離對象與臨時對象的區別在於:前者是由持久化對象轉變過來的,並且在數據庫中還存在與之對應的記錄,而後者在數據庫中沒有與之對應的記錄;
v 進入遊離狀態的條件
§ 當調用session的close方法的時候,session緩存被清空,緩存中的所有持久化對象都變爲遊離狀態。如果此時再沒有其它變量引用的時候,其生命週期結束
§ session的evict方法能夠從緩存中刪除一個持久化對象,使它變爲遊離狀態。如果內存中存在大量的對象的時候,可以通過這個方法來刪除緩存中的對象(不建議使用這個方法,還是使用查詢的方法和常規方法來處理對象在內存中的深度)
比較一下,下面的兩個程序之間有是麼區別?
Customer c=new Custoemr();
c.setName(“tom”);
session.save(c);
tx.commit();
Customer c=new Custoemr();
session.save(c);
c.setName(“tom”);
tx.commit();
v 以上兩段對數據庫的操作,雖然完成相同的功能,但是,生成的SQL語句卻不同。
v 第一個生成一條insert語句,將customer對象存儲到數據庫中;而第二段代碼生成兩條SQL語句,一條insert和一條update
總結:
v 對象的OID來維持對象和數據庫記錄之間的對應關係。當Customer對象處於持久化狀態的時候,不允許改變OID的值。
v Customer c=new Customer();
session.save(c);
c.setId(new Long(6));//HibernateException
v session的save方法是用來持久化一個臨時對象,程序中不應該把持久化對象和遊離對象傳給save方法(多餘的操作)
Session的update方法
v 使一個遊離對象轉變成持久化對象
v 把對象重新加入到緩存中,使它變爲持久化對象;計劃執行update語句,在清空緩存的時候真正的執行SQL
v class的select-before-update屬性;如果想要session僅僅在對象的屬性發生變化的時候才執行update,可以把這個屬性設置爲true;但是這個屬性會在執行update操作之間,執行一個select操作(這樣會對數據庫多一次查詢操作,所以要根據需求來選用這個屬性)
Session的saveOrUpdate方法
v 包含了save和update方法的功能,如果傳入的參數是臨時對象,就調用save方法;如果傳入是遊離狀態,就調用update方法;如果傳入的對象是持久化對象,就直接返回;
v Hibernate判斷臨時對象的標準:
§ Java的OID取值爲null
§ Java對象具有version屬性,並取值爲null
§ 映射配置文件id元素設置了unsaved-value屬性,並且OID的取值與unsaved-value取值匹配
§ 自定義了Hibernate的Interceptor實現類,並且Interceptor的isUnsaved方法返回Boolean.TRU
原文地址:http://blog.csdn.net/joe_007/article/details/6959126hibernate緩存機制(三)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.