其實這些內容應該算是進階部分的內容,常常可以用到。分享給大家。
Criteria Query
通常也稱為
QBC
,這種查詢最大的好處就是不用拼接
HQL
或
SQL
語句。
基本用法如下:
Criteria crit=session.createCriteria(User.class);
查詢條件表達式使用:
Expression
示例查詢使用:
Example
,此類已經實現
Criterion
接口,它也可以用作
Criteria
的查詢條件。
其作用是:根據已有對象,查找屬性與之相符的其他對象。常用的場景是組合查詢。
我們可以通過
Criteria.createCriteria
方法在原有
Criteria
對象的基礎上構建復合查詢。
DetachedCriteria
可以脫離
Session
實例獨立存在,這樣,我們就可以將某些通用的
Criteria
查詢條件進行抽離,每次使用時再與當前
Session
實例綁定以獲得更好的代碼重用效果。它也可以用於子查詢表達(
Subqueries
)。
Criteria
的分組和統計采用
Projections
類來搞定。如下
:
Criteria.setProjection(Projections.groupProperty(
“
age
”
));
HQL
HQL
是最常用的方式,在使用時最好能用參數綁定的方式,否則可能會帶來下面三個問題:
A、 編碼更加零亂,可讀性降低。
B、難以進行性能優化,根據JDBC以及數據庫操作原理可知,每次SQL執行時,數據庫都對SQL語法進行解析和優化,並將其處理結果保存在緩存中,如果之後有參數不同,語法相同的SQL命令,則直接以此緩存結果加以執行,從而避免SQL解析和優化的開銷。另外,從Hibernate角度而言,它使用了PreparedStatement作為底層數據庫訪問手段,對於相同的SQL,也可以重用已經創建的PreparedStatement對象。
C、引入額外的安全風險,SQL Injection是常見的系統玫擊手段,這種方法的目標即針對由SQL字符串拼裝造成的漏洞。如在用戶名欄中輸入:a or ‘x’=’x 這樣的字符串。
參數綁定有兩種方式,一種是順序綁定,一種是引用綁定。
引用查詢
將
HQL
語句寫在
Mapping XML
文件中。
Query query=session.getNameQuery(
“
queryByName
”
);
Hibernate3
中也支持存儲過程。
聯合查詢
聯合查詢是很有必要復習一下的知識,我想很多人可能都不能完全透徹的說清楚常用的四種聯合查詢,即:
inner join , left join , right join , full join
Inner join
返回所有滿足關聯條件的記錄組合。
Left join
返回的結果集中,包含了左邊表符合條件的所有記錄及其對應的右邊表的記錄(如無,則以
NULL
替代)。
Right join
與
left join
正好相反。
Full join
是
left join
與
right join
的並集。比較少用。
注意:
fetch
只對
inner join
和
left join
有效,
其意思是讓右邊的表立即取出。
另外,對兩張表進行笛卡爾積的查詢也比較少用,聽起來就有些恐怖。如
:
from User,Address
在
Hibernate
的世界里,有四種數據加載的方式:
即時加載(
Immediate Loading
),延遲加載(
Lazy Loading
),預先加載(
Eager Loading
),批量加載(
Batch Loading ,batch-size
應該設定為一個合理的小型數值,一般
<10
)。
自定義持久化實現
有時候可能還真的有用途,比如每個表都有的一些公共字段。在
Mapping XML
文件中指定,如下:
<sql-insert>
INSERT INTO USER(ID,NAME,AGE) VALUE(?,?,?)
</sql-insert>
<sql-update>
UPDATE USER SET NAME=? AGE=? WHERE ID=?
</sql-update>
<sql-delete>
DELETE FROM USER WHERE ID=?
</sql-delete>
Hibernate
中實體對象的三種狀態
Transient
(自由狀態),
Persistent
(持久狀態),
Detached
(游離狀態)
Hibernate
中判定對象處於
Detached
狀態還是
Transient
狀態時,有著十分復雜的機制:
1、首先,對象的ID屬生是否為null。
2、根據條件進行判定。
3、如果指定了ID屬性的unsaved-value,即麼id屬性是否等於unsaved-value。
4、
如果配備了
version
屬性,
version
屬性是否為
null
。
5、如果配備了version屬性,且為version指定了unsaved-value,version屬性值是否等於unsaved-value。
6、如果存在Interceptor,即麼Interceptor.isUnsaved方法是否返回true。
臟數據檢查
臟數據是指一個數據對象所攜帶的信息發生了改變之後的狀態。
臟數據檢查一般策略大致有下面兩種:
1、數據對象監控,其實現方式大體上是通過攔截器對數據對象的setter進行攔截,攔截器的實現可以借助Dynamic Proxy或者CGlib實現。
2、數據版本比對,在持久層框架中維護數據對象的最近讀取版本,當數據提交時將提交數據與此版本進行比對,如果發生變化則將其同步到數據相應的庫表。
Hibernate
采用第二種檢查策略。
Unsaved-value
數據保存時,
Hibernate
將根據這個值來判斷對象是否需要保存,用於非顯示保存的場景。所謂顯示保存,是指在代碼中明確調用
session
的
save, update, saveOrUpdate
方法對對象進行持久化。
數據緩存
數據緩存策略包括三個層次:事務級緩存(基於
Session
的生命周期實現),應用級
/
進程級緩存(在
SessionFactory
層實現,在
Cluster
環境中一定要特別注意這類
Cache
),分布式緩存
(
其效果尚需結合實際情況考証
)
。
Hibernate
數據緩存分為兩個層次:內部緩存
(
Session Level
,也稱一級緩存),二級緩存(
SessionFactory Level
,也稱二級緩存)。
將在以下情況中發揮作用:通過
id[
主鍵
]
加載數據時和延遲加載時。
內部緩存正常情況下由
Hibernate
自動維護,如果需要手動干預,我們可以通過以下方法完成:
Session.evict()
將某個特定對象從內部緩存中清除,
Session.clear()
清空內部緩存。
二級緩存涵蓋了應用緩存和分布式緩存領域,在引入時必須考慮以下問題:數據庫是否與其他應用共享,應用是否需要部署在集群環境中。
如果數據滿足以下條件,則可以將其納入緩存管理:
1、數據不會被第三方應用修改。
2、數據大小(Data size)在可接受的范圍之內。
3、數據更新頻率較低。
4、
同一數據可能會系統頻繁引用。
5、
非關鍵數據。
Hibernate
本身並未提供二級緩存的產品化實現(只提供了一個基於
Hashtable
的簡單緩存以供調試)。第三方緩存實現有:
JCS
,
EHCache, OSCache, JBossCache, SWarmCache
,僅
JBossCache
和
SwarmCache
支持
Cluster
。
SwarmCache
提供的是
invalidation
方式的分布式緩存,即當集群中的某個節點更新了緩存中的數據,即通知集群中的其他節點將此數據廢除,之後各節點需要用到這個數據的時候,會重新從數據庫中讀入並填充到緩存中。
JBossCache
提供的是
Repplication
式的緩存,即如果集群中某個節點的數據發生改變,此節點會將發生改變的數據的最新版本復制到集群中的每個節點中以保持所有節點狀態一致。啟用二級緩存,需要在
hibernate.cfg.xml
中配置以下參數:
<property name=
”
hibernate.cache.provider_class
”
>
net.ehcache.hibernate.Provider
</property>
Hibernate
提供以下
4
種內置的緩存同步策略:
Read-only
:只讀,對於不會發生改變的數據,可使用只讀型緩存。
Nonstrict-read-write
:如果程序對並發訪問下的數據同步要求不同非常嚴格,且數據更新操作頻率較低,可采用本選項,獲得較好性能。
Read-write
:嚴格可讀寫緩存,基于時間戳判定機制,實現了“
read committed
”
事務隔離等級。可用於對數據同步要求嚴格的情況,但不支持分布式緩存。
Transactional
:事務型緩存,必須運行在
JTA
事務環境中。
Hibernate
的默認事務處理機制基於
JDBC Transaction
。
我們也可以通過配置文件設定采用
JTA
作為事務管理實現:
<property name=
”
hibernate.transaction.factory_class
”
>
net.hibernate.transaction.JTATransactionFactory
</property>
JTA
提供了跨
Session
的事務管理能力(
JDBC
事務不支持)。
Hibernate
支持兩種鎖機制,悲觀鎖(
perssimistic locking
)和樂觀鎖(
optimistic locking
)。
悲觀鎖主要是利用數據庫底層的機制來實現的,加鎖模式有:
LockMode.None
:無鎖機制
LockMode.WRITE
:
Insert
和
Update
記錄時會自動獲取
LockMode.READ
:讀取記錄時會自動獲取
LockMode.UPGRADE
:利用數據庫的
for update
子句加鎖
LockMode.UPGRADE_NOWAIT
:
Oracle
的特定實現,利用
Oracle
的
for update nowait
子句實現加鎖。
加鎖一般通過以下方式實現:
Criteria.setLockMode
Query.setLockMode
Session.lock
樂觀鎖,大多是基於數據版本(
version
)記錄機制實現。即為數據增加一個版本標識,在基於數據庫表的版本解決方案中,一般是通過為數據庫表增加一“
version
”
字段來實現。讀取出數據時,將此版本號一同讀出,之後更新時,對此版本號加
1
。此時,將提交數據的版本數據與數據庫表對應記錄的當前版本信息進行比對,如果提交的數據版本號大於數據庫當前版本號,則予以更新,否則認為是過期數據。(註,感覺跟
CVS
版本的機制差不多)
Hibernate
中可以通過
Class
描述符的
optimistic-lock
屬性結合
version
描述符指定。
<class name=”User” table=”t_user” optimistic-lock=”version”>
<id>…</id>
<version column=”version” name=”version” type=”string” />
<!-- version
必須放在
id
之後
-->
…
</class>
Optimistic-lock
有四個選項:
none
,無樂觀鎖,
version
,通過版本機制控制實現樂觀鎖(官方推荐的方式,也是目前惟一在實體脫離
session
發生修改的情況下依然有效的鎖機制),
dirty
,通過檢查發生變動過的屬性實現樂觀鎖,
all
,通過檢查所有屬性實現樂觀鎖。
持久層操作
數據加載
get()/load()
方法的主要區別在於:
1
、未發現記錄時,
get
返回
null
,
load
拋出
ObjectNotFoundException
。
2
、
load
可返回實體的代理實例,
get
方法永遠直接返回實體類。
3
、
load
充分利用
Level 2 Cache
,而
get
僅在內部緩存中進行數據查找。
Find
()
方法只查找一次,
iterate
()
方法是
N+1
次查詢(先查出符合條件的
ID
,然后再根據
ID
每一筆記錄依次查出),但會充分利用
Cache
,要學會分情況利用。
對於海量數據進行操作,可能會導致
OutOfMemoryError
的解決方案之一是,采用
iterate()
方法逐條對記錄進行處理,如:
Iterator it=session.iterator(…);
While(it.hasNext()){
Object obj=it.next();
Session.evict(obj);
SessionFactory.evict(obj.getClass(),obj.getId());
}
一般,對於這種特大數據量的處理,還是推荐使用
SQL
語句或存儲過程來解決。
QueryCache
只在兩種情況下產生作用:
1
、完全相同的
select SQL
重復執行,
2
、在兩次查詢之間,此
select SQL
對應的庫表沒有發生過變化。使用方式:
配置中:
hibernate.cache.use_query_cache=true
查詢時:
query.setCacheable(true);
Hibernate.initialize()
方法可以強制
Hibernate
立即加載關聯的對象集。
Hibernate2
中支持索引和實體延遲加載,
Hibernate3
中還支持屬性延遲加載,但需要對
POJO
實體作一些增加處理。
數據批量導入:
hibernate.jdbc.batch_size=25
,比較適合於遠程數據庫的數據插入、更新、刪除操作。
Hibernate
中基於游標的用法:
Transaction tx=session.beginTransaction();
String hql=”from User”;
Query query=session.createQuery(hql);
ScrollableResults scRes=query.scroll();
while(scRes.next()){
User user=(User)scRes.get(0);
}
tx.commit();
Hibernate3
中雖然支持
Bulk delete/update
,實際上仍然沒有解決
Cache
同步上的問題,無法保証緩存數據的一致有效性(包括內部緩存和二級緩存),
Hibernate
與其它方式(如
JDBC
)在一個系統中混用也會帶來同樣的問題。
Hibernate
中涉及的
Collection
類型共有以下幾種:
無序集:
Set , Bag , Map
有序集:
List
Bag
的底層是錯助一個
List
實現,但卻屏蔽了
List
的有序特性。更新時,
bag
的實現方式實際上是先將數據庫表中的所有的集合數據全部刪除,再將現有數據逐條插入。利用
idbag
(作為
Bag
的一種延伸),則成功地解決了這個問題。
<idbag name=”address” lazy=”true” table=”t_address”>
<collection-id type=”int” column=”id”>
<generator class=”identity” />
</collection-id>
<key column=”user_id” />
</idbag>
與
Set
配置相比,
Map
增加了一個
index
配置,用於指定用作
Key
的字段名:此字段要求在數據集中取值惟一。
數據排序有兩種方式:
sort
和
order-by
Sort=”natural”
指定采用
Java
默認的排序機制,它會調用相應數據類型的
compareTo
方法進行排序中的值比對。
也可以指定為自定義的實現。
posted on 2007-02-09 17:26
Robin's Programming World 阅读(5280)
评论(0) 编辑 收藏 所属分类:
Java