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