推遲加載:
推遲加載機制是號碼大全爲了防止一些無謂的功用開支而提出來關鍵詞挖掘工具的,所謂推遲加載即是當在真實需求數據的時分,才真實履行數據加載操作。在Hibernate中供給了對實體方針的推遲加載以及對調集的推遲加載,另外在Hibernate3中還供給了對特點的推遲加載。下面咱們就別離介紹這些品種的推遲加載的細節。
A、實體方針的推遲加載:
假如想對實體方針運用推遲加載,有必要要在實體的映射裝備文件中進行相應的裝備,如下所示:
……
經過將class的lazy特點設置爲true,來敞開實體的推遲加載特性。假如咱們運轉下面的代碼:
User user=(User)session.load(User.class,”1”);(1)
System.out.println(user.getName());(2)
當運轉到(1)處時,Hibernate並沒有建議對數據的查詢,假如咱們此刻經過一些調試東西(比方JBuilder2005的Debug東西),調查此刻user方針的內存快照,咱們會驚奇的發現,此刻回來的可能是User$EnhancerByCGLIB$$bede8986類型的方針,並且其特點爲null,這是怎麼回事?還記得前面我曾講過session.load()辦法,會回來實體方針的署理類方針,這兒所回來的方針類型即是User方針的署理類方針。在Hibernate中經過運用CGLIB,來完結動態結構一個方針方針的署理類方針,並且在署理類方針中包含方針方針的一切特點和辦法,並且一切特點均被賦值爲null。經過調試器顯現的內存快照,咱們能夠看出此刻真實的User方針,是包含在署理方針的CGLIB$CALBACK_0.target特點中,當代碼運轉到(2)處時,此刻調用user.getName()辦法,這時經過CGLIB賦予的回調機制,實踐上調用CGLIB$CALBACK_0.getName()辦法,當調用該辦法時,Hibernate會首先查看CGLIB$CALBACK_0.target特點是不是爲null,假如不爲空,則調用方針方針的getName辦法,假如爲空,則會建議數據庫查詢,生成相似這樣的SQL句子:select * from user where id=’1’;來查詢數據,並結構方針方針,並且將它賦值到CGLIB$CALBACK_0.target特點中。
這樣,經過一箇中心署理方針,Hibernate完結了實體的推遲加載,只要當用戶真實建議獲得實體方針特點的動作時,才真實會建議數據庫查詢操作。所以實體的推遲加載是用經過中心署理類完結的,所以只要session.load()辦法纔會運用實體推遲加載,由於只要session.load()辦法纔會回來實體類的署理類方針。
B、調集類型的推遲加載:
在Hibernate的推遲加載機制中,對於調集類型的運用,含義是最爲嚴重的,由於這有可能使功用得到大幅度的提高,爲此Hibernate進行了很多的盡力,其間包括對JDK Collection的獨立完結,咱們在一對多相關中,定義的用來容納相關方針的Set調集,並不是java.util.Set類型或其子類型,而是net.sf.hibernate.collection.Set類型,經過運用自定義調集類的完結,Hibernate完結了調集類型的推遲加載。爲了對調集類型運用推遲加載,咱們有必要如下裝備咱們的實體類的對於相關的有些:
…..
經過將元素的lazy特點設置爲true來敞開調集類型的推遲加載特性。咱們看下面的代碼:
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses(); (1)
Iterator it=addset.iterator(); (2)
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
當程序履行到(1)處時,這時並不會建議對相關數據的查詢來加載相關數據,只要運轉到(2)處時,真實的數據讀取操作纔會開端,這時Hibernate會依據緩存中契合條件的數據索引,來查找契合條件的實體方針。
這兒咱們引入了一個全新的概念——數據索引,下面咱們首先將講一下啥是數據索引。在Hibernate中對調集類型進行緩存時,是分兩有些進行緩存的,首先緩存調集中一切實體的id列表,然後緩存實體方針,這些實體方針的id列表,即是所謂的數據索引。當查找數據索引時,假如沒有找到對應的數據索引,這時就會一條select SQL的履行,獲得契合條件的數據,並結構實體方針調集和數據索引,然後回來實體方針的調集,並且將實體方針和數據索引歸入Hibernate的緩存之中。另一方面,假如找到對應的數據索引,則從數據索引中取出id列表,然後依據id在緩存中查找對應的實體,假如找到就從緩存中回來,假如沒有找到,在建議select SQL查詢。在這兒咱們看出了另外一個疑問,這個疑問可能會對功用產生影響,這即是調集類型的緩存戰略。假如咱們如下裝備調集類型:
…..
這兒咱們運用了裝備,假如選用這種戰略來裝備調集類型,Hibernate將只會對數據索引進行緩存,而不會對調集中的實體方針進行緩存。如上裝備咱們運轉下面的代碼:
User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses();
Iterator it=addset.iterator();
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
}
System.out.println(“Second query……”);
User user2=(User)session.load(User.class,”1”);
Collection it2=user2.getAddresses();
while(it2.hasNext()){
Address address2=(Address)it2.next();
System.out.println(address2.getAddress());
}
運轉這段代碼,會得到相似下面的輸出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Select * from address where id=’1’;
Select * from address where id=’2’;
Tianjin
Dalian
咱們看到,當第2次履行查詢時,履行了兩條對address表的查詢操作,爲啥會這樣?這是由於當第一次加載實體後,依據調集類型緩存戰略的裝備,只對調集數據索引進行了緩存,而並沒有對調集中的實體方針進行緩存,所以在第2次再次加載實體時,Hibernate找到了對應實體的數據索引,可是依據數據索引,卻無法在緩存中找到對應的實體,所以Hibernate依據找到的數據索引建議了兩條select SQL的查詢操作,這兒造成了對功用的糟蹋,怎樣才能防止這種狀況呢?咱們有必要對調集類型中的實體也指定緩存戰略,所以咱們要如下對調集類型進行裝備:
…..
此刻Hibernate會對調集類型中的實體也進行緩存,假如依據這個裝備再次運轉上面的代碼,將會得到相似如下的輸出:
Select * from user where id=’1’;
Select * from address where user_id=’1’;
Tianjin
Dalian
Second query……
Tianjin
Dalian
這時將不會再有依據數據索引進行查詢的SQL句子,由於此刻能夠直接從緩存中獲得調集類型中寄存的實體方針。
C、特點推遲加載:
在Hibernate3中,引入了一種新的特性——特點的推遲加載,這個機制又爲獲取高功用查詢供給了有力的東西。在前面咱們講大數據方針讀取時,在User方針中有一個resume字段,該字段是一個java.sql.Clob類型,包含了用戶的簡歷信息,當咱們加載該方針時,咱們不得不每一次都要加載這個字段,而不論咱們是不是真的需求它,並且這種大數據方針的讀取自身會帶來很大的功用開支。在Hibernate2中,咱們只要經過咱們前面講過的面功用的粒度細分,來分化User類,來解決這個疑問(請參照那一節的論述),可是在Hibernate3中,咱們能夠經過特點推遲加載機制,來使咱們獲得只要當咱們真實需求操作這個字段時,纔去讀取這個字段數據的才能,爲此咱們有必要如下裝備咱們的實體類:
……
經過對元素的lazy特點設置true來敞開特點的推遲加載,在Hibernate3中爲了完結特點的推遲加載,運用了類增強器來對實體類的Class文件進行強化處置,經過增強器的增強,將CGLIB的回調機制邏輯,參加實體類,這兒咱們能夠看出特點的推遲加載,仍是經過CGLIB來完結的。CGLIB是Apache的一個開源工程,這個類庫能夠操作java類的字節碼,依據字節碼來動態結構契合要求的類方針。依據上面的裝備咱們運轉下面的代碼:
String sql=”from User user where user.name=’zx’ ”;
Query query=session.createQuery(sql); (1)
List list=query.list();
for(int i=0;i User user=(User)list.get(i);
System.out.println(user.getName());
System.out.println(user.getResume()); (2)
}
當履行到(1)處時,會生成相似如下的SQL句子:
Select id,age,name from user where name=’zx’;
這時Hibernate會檢索User實體中一切非推遲加載特點對應的字段數據,當履行到(2)處時,會生成相似如下的SQL句子:
Select resume from user where id=’1’;
這時會建議對resume字段數據真實的讀取操作。
---------------------------------
推遲加載的方針:
hibernate 2對於實體方針和調集
hibernate 3一起供給了特點的推遲加載功用。
其間對調集的推遲加載特性含義最爲嚴重。
實體方針的推遲加載:
1.在hibernate裝備文件中的class指定
調集類型的推遲加載:
在set中指定lazy=true
這樣只要實踐加載與方針相相關的調集方針的時分,再經過session從數據庫中加載實踐的數據集。
Hibernate.initialize辦法能夠強制Hibernate當即加載相關的方針集,例如:
Hibernate.initialize(user.getAddress());
調集類型的緩存:
假如爲某個調集類設定了緩存,如
name="address"
table="t_address"
lazy="true"
......
>
Hibernate對調集類型進行緩存的時分,分兩有些保留。首先是這個調集中一切實體的id列表,其次纔是各個實體方針。
這兒制定了cache usage="read-only"只會使得Hibernate對數據索引進行緩存。也即是說只緩存了調集中的數據索引,並不包含調集中的各個實體元素。
假如指定cache usage="read-write"纔會對調集中的實體進行緩存。
特點的推遲加載:
在property節點中聲明lazy=true,並且還需求憑藉Hibernate類增強器對POJO類的二進制Class文件進行強化處置。
hibernate的推遲加載通用辦法
public class HibernateUtil extends HibernateDaoSupport {
//用法:instance = getHibernateTemplate().find("from FxjlbVO");
// super.initialize(instance, "getFxjlbChjs");
public void initialize(Object object, String methodName)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
String[] methodArray = methodName.split("/.");
Method method = null;
Object initializeObject = object;
if (methodArray.length == 1) {
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
method = object.getClass()
.getMethod(methodArray[0], new Class[] {});
initializeObject = method.invoke(initializeObject, new Object[] {});
this.getHibernateTemplate().initialize(initializeObject);
} else {
for (int i = 0; i < methodArray.length; i++) {
method = initializeObject.getClass().getMethod(methodArray[i],
new Class[] {});
initializeObject = method.invoke(initializeObject,
new Object[] {});
}
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
public void initialize(Object object, String methodName[])
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
for (int i = 0; i < methodName.length; i++) {
String[] methodArray = methodName[i].split("/.");
Method method = null;
Object initializeObject = object;
if (methodArray.length == 1) {
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
method = object.getClass().getMethod(methodArray[0],
new Class[] {});
initializeObject = method.invoke(initializeObject,
new Object[] {});
//等價於:initializeObject=PropertyUtils.getProperty(initializeObject,methodArray[0]);
this.getHibernateTemplate().initialize(initializeObject);
} else {
for (int j = 0; j < methodArray.length; j++) {
method = initializeObject.getClass().getMethod(
methodArray[j], new Class[] {});
initializeObject = method.invoke(initializeObject,
new Object[] {});
}
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
}
// fInitializeFields是調調集,不是辦法名
//instance = getHibernateTemplate().find("from FxjlbVO");
// HashSet aa=new HashSet();
// aa.add("fxjlbChjs");
// super.initialize(instance, aa);
public void initialize(Object object, HashSet fInitializeFields)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
String[] methodName = new String[fInitializeFields.size()];
methodName = (String[]) fInitializeFields.toArray(methodName);
for (int i = 0; i < methodName.length; i++) {
String[] methodArray = methodName[i].split("/.");
Method method = null;
- indexRead arguments from command-line "http://www.shoudashou.com"
- indexRead arguments from command-line "http://www.4lunwen.cn"
- indexRead arguments from command-line "http://www.zx1234.cn"
- indexRead arguments from command-line "http://www.penbar.cn"
- indexRead arguments from command-line "http://www.whathappy.cn"
- indexRead arguments from command-line "http://www.lunjin.net"
- indexRead arguments from command-line "http://www.ssstyle.cn"
- indexRead arguments from command-line "http://www.91fish.cn"
- indexRead arguments from command-line "http://www.fanselang.com"
Object initializeObject = object;
if (methodArray.length == 1) {
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
initializeObject=PropertyUtils.getProperty(initializeObject,methodArray[0]);
this.getHibernateTemplate().initialize(initializeObject);
} else {
for (int j = 0; j < methodArray.length; j++) {
initializeObject=PropertyUtils.getProperty(initializeObject,methodArray[0]);
}
this.getHibernateTemplate().lock(initializeObject,
org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(initializeObject);
}
}
}
public void initialize(Collection collection, HashSet fInitializeFields)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
for (Iterator i = collection.iterator(); i.hasNext();) {
Object object = i.next();
this.initialize(object, fInitializeFields);
}
}
public void initialize(Object object) throws SecurityException,
NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
this.getHibernateTemplate().lock(object, org.hibernate.LockMode.NONE);
this.getHibernateTemplate().initialize(object);
}
public void initialize(Collection collection, String methodName[])
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, IllegalAccessException,
InvocationTargetException {
for (Iterator i = collection.iterator();i.hasNext(); ) {
Object object = i.next();
this.initialize(object, methodName);
}
}