隨筆-193  評(píng)論-715  文章-1  trackbacks-0

          其實(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-valueversion屬性值是否等於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)。

          posted on 2007-02-09 17:26 Robin's Programming World 閱讀(5284) 評(píng)論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 堆龙德庆县| 呼伦贝尔市| 通辽市| 叙永县| 丹寨县| 长治市| 闸北区| 奉贤区| 响水县| 上饶市| 乐平市| 碌曲县| 汨罗市| 江西省| 泾源县| 太和县| 宽城| 浦城县| 晋中市| 长宁县| 莲花县| 噶尔县| 通河县| 建始县| 泸西县| 东乌珠穆沁旗| 汉源县| 张家口市| 平顶山市| 元阳县| 改则县| 盐源县| 西宁市| 浦县| 宁南县| 麻城市| 古交市| 威远县| 建瓯市| SHOW| 景洪市|