Hibernate雜項

文章引用於:http://blog.csdn.net/javakevin/archive/2007/12/28/1999035.aspx

1,數據加載

1),Session.get/load
區別:(1),未發現符合條件的記錄:get-->null,load-->ObjectNotFoundException。
(2),load可返回實體的代理類實例,get永遠直接返回實體類。
(3),load-->內部緩存-->二級緩存-->SQL(DB),get-->內部緩存-->SQL(DB)。

Session加載實體對象時經過的過程:
內部緩存(查找數據)-->NonExists(查找查詢條件)-->第二級緩存 (load方法)-->Select SQL(DB)-->根據Result創建對應的數據對象-->將其數據對象納入當前Session實體管理容器(內部緩存)-->執 行Interceptor.onLoad-->納入二級緩存-->如果數據對象實現了LifeCycle接口,則調用數據對象的onLoad 方法-->返回數據對象。

2),Session.find/iterate
Session.find()------->session.createQuery().list()-----無法利用緩存,它對緩存只寫不讀。
Session.iterate()---->session.createQuery().iterate()-----可以充分利用緩存。
-------基於充分利用緩存以提升性能上的考量。
內存使用上的考慮:對海量數據進行操作,find方法一次獲得所有的記錄並將其讀入內存-->內存消耗甚至OutOfMemoryError。
解決方案之一:逐條對記錄進行處理,將內存消耗保持在可以接受的範圍之內。
String hql = "from TUser where age > ?";
Iterator it = session.iterate(hql,new Integer(18),Hibernate.INTEGER);
while(it.hasNext()){
TUser user = (TUser)it.next();
session.evict(user);//將對象從一級緩存中移除
sessionFactory.evict(TUser.class,user.getId());//將對象從二級緩存中移除
}
解決方案之二:SQL或存儲過程。

3),Query Cache
---中保存了之前查詢操作執行過的Select SQL,以及由此查詢產生的查詢結果集(包括查詢對象的類型和id)。

根據查詢SQL--->從Query Cache中檢索--->取出這個SQL的檢索結果集--->根據這個結果集中對象類型及其id,從緩存中取出對贏得實體對象返回。

Query Cache只在特定的情況下產生作用:
(1),完全相同的Select SQL重複執行。
(2),在兩次查詢之間,此Select SQL對應的庫表沒有發生過改變。

<hibernate-configuration>
<session-factory>
....
<property name="hibernate.cache.use_query_cache">true</property>
....
</session-factory>
<hibernate-configuration>

String hql="from TUser where age > ?";
Query query = session,createQuery(hql).setInteger(0,20);
query.setCacheable(true);

List userList = query.list();
int len = userList.size();
for(int i=0;i<len;i++){
TUser user = (TUser)userList.get(i);
}

query = session2.createQuery(hql).setInteger(0,20);
query.setCacheable(true);//第二次查詢時,也必須將Cacheable設爲true

userList = query.list();
len = userList.size();
for(int i=0;i<len;i++){
TUser user = (TUser)userList.get(i);
}
看到第二次查詢時,Hibernate並沒有執行任何Select SQL即完成了任務,這就是Query Cache的作用。

4),延遲加載(Lazy Loading)
---爲了避免在某些情況下,關聯關係所帶來的無謂的性能開銷。---即在需要數據的時候,才真正執行數據加載操作。

Hibernate2延遲加載實現主要針對:(1),實體對象;(2),集合。
Hibernate3同時提供了屬性的延遲加載功能。

(1),實體對象的延遲加載
<class ... laze="true"> ---Hibernate2中,laze屬性默認爲false,Hibernate3中其默認值爲true。
Hibernate 的代理機制:Hibernate中引入了CGLib作爲代理機制實現的基礎。CGLib可以在運行期動態生成Java Class,這裏的代理機制,其基本實現原理就是通過由CGLib構造一個包含目標對象所有屬性和方法的動態對象(相當於動態構造目標對象的一個字類)返 回,並以之作爲中介,爲目標對象提供更多的特性。真正的TUser對象位於代理類的CGLIB$CALLBACK_0.target屬性中。
-----只有當客戶程序真正調用實體類的取值方法時,Hibernate纔會執行數據庫查詢操作。

(2),集合類型的延遲加載
<set ... lazy="true">
Hibernate.initialize方法可以強制Hibernate立即加載關聯對象集。
Hibernate.initialize(user.getAddresses());
session.close();
//通過Hibernare.initialize方法強制讀取數據,addresses對象即可脫離session進行操作
Set hset = user.getAddresses();
TAddress addr = (TAddress)hset.toArray()[0];

(3),屬性的延遲加載
<property ... lazy="true">
與實體和集合類型的延遲加載不同,Hibernate3屬性延遲加載機制在配置之外,還需要藉助類增強器對二進制Class文件進行強化處理。

5),數據保存

Session.save方法用於實體對象到數據庫的持久化操作。
包含步驟:在Session內部緩存中尋找待保存對象 -->lifecycle(onSave())-->Validatable (validate())-->Interceptor.onSave()-->構造Insert SQL-->user.id=new id-->將user對象放入內部緩存-->對級聯關係進行遞歸處理。

Session.update:根據待更新實體對象的Key在當前session的內部緩存中進行查找(一個Persistent實體對象調用update並不會產生作用)-->初始化實體對象的狀態信息(作爲之後髒數據檢查的依據),並將其納入內部緩存。

Session.saveOrUpdate:實際上是save和update方法的組合應用,它本身並沒有增加新的功能特性,但是卻爲我們的應用層開發提供了一個相當便捷的功能選擇。--無需關心傳入的user參數到底是怎樣的狀態。
public interface IUserDAO{
public TUser getUser(String id);
public void saveUser(TUser user);
}

6),數據批量操作

(1),數據批量導入
<session-factory>
...
<property name="hibernate.jdbc.batch_size">25</property>
...
</session.factory>

public void importUserList() throws HibernateException{
Transaction tx = session.beginTransaction();
for(int i=0;i<10000;i++){
TUser user = new TUser();
user.setName("user" + i);
session.save(user);

if(i%25==0){ //以每25個數據作爲一個處理單元
session.flush();
session.clear();
}
}
tx.commit();
}

(2),數據批量刪除

內存消耗:
Transaction tx = session.beginTransaction();
String hql = "from TUser";
Query query = session.createQuery(hql);
ScrollableResults scRes = query.scroll();
while(scRes.next()){
TUser user = (TUser)scRes.get(0);
session.delete(user);
}
tx.commit();

迭代刪除操作的執行效率:採用調整hibernate.jdbc.batch_size參數來解決。

BULK delete/update:
Transaction tx = session.beginTransaction();
String hql = "delete TUser";
Query query = session.createQuery(hql);
int ret = query.executeUpdate();
tx.commit();
--------批量刪除與緩存管理的矛盾仍然存在。---關閉二級緩存,調用不同session解決內部緩存帶來的問題。

7),Collection

(1),Collection類型(org.hibernate.collection)
無序集:Set,Bag,Map
有序集:List
---無序與有序,是針對Hibernate數據持久過程中,是否保持數據集合中的記錄排列輸序加以區分的。

Set:
陷阱--->
<set name="addresses" table="t_address" lazy="false">
<key column="user_id"/>
<one-to-many class="TAddress"/>
</set>
<set name="addresses" table="t_address" lazy="false">
<key column="user_id"/>
<element type="string" column="address"/>
</set>

Bag:允許包含重複元素的“Set”。---基於List但屏蔽其有序性。
idbag:
<idbag name="addresses" lazy="true" table="t_address">
<collection-id type="int" column="id">
<generator class="identity"/>
</collention-id>
<key column="user_id">
<element type="string" column="address"/>
</idbag>

Map:鍵值對應關係。
<map name="addresses" lazy="true" table="t_address">
<key column="user_id"/>
<index type="string" column="type"/>
<element type="string" column="address"/>
</map>
index:要求在數據集中取值唯一。
TUser user = (TUser)session.load(TUser.class,new Integer(1));
user.getAddresses().get("Home");//讀取家庭地址
user.getAddresses().get("Office");//讀取辦公地址

List:實現了集合內元素順序的持久化。
<list name="addresses" lazy="true" table="t_address">
<key column="user_id"/>
<index type="integer" column="idx"/>
<element type="string" column="address"/>
</list>

8),結果集排序
排序強調的是針對現有數據,以特定的邏輯對其排列此序進行調整,而排序的結果,是數據在內存中的某種排列次序,屬於臨時狀態。

排序方式:
Sort--->Collection中的數據排序,如對一個List中的元素先後進行排序調整。(JVM)
<set ... sort="natural".../>
如果期望指定某種特殊的排序算法,那麼可以實現java.util.Comparator接口,如:
package org.sample
public class LengthComparator implements Comparator{
public int compare(Object obj1,Object obj2){
String str1 = String.valueOf(Obj1);
String str2 = String.valueOf(Obj2);
return str1.length()-str2.length();
}
}
<set ... sort="org.sample.LengthComparator".../>
---Bag,List不支持sort排序方式。

order-by--->對數據庫執行Select SQL時,由order by子句實現的數據排序方式。(數據庫)
<set ... order-by="address desc".../>
List不支持order-by排序。

發佈了38 篇原創文章 · 獲贊 0 · 訪問量 1760
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章