1、事務(wù)
1-1、類別
● 本地事務(wù)
如果事務(wù)只和一個(gè)資源管理器有關(guān),則為本地事物。在本地事務(wù)中,事務(wù)管理器只是將事務(wù)的管理委托給底層的資源管理器。
● 分布式事務(wù)
分布式事務(wù)和多個(gè)可能不同的資源管理器以一種協(xié)調(diào)的方式進(jìn)行交互。
1-2、Java 中事務(wù)處理
JDBC 事務(wù):由底層數(shù)據(jù)庫(kù)事務(wù)管理器控制,操作比較簡(jiǎn)單,但是不適合控制多個(gè)應(yīng)用程序組件的事務(wù),并且沒(méi)有傳播的上下問(wèn)。
JTA 和 JTS:Java 事務(wù) API 和 Java 事務(wù)服務(wù),可以跨越多個(gè)組件和數(shù)據(jù)庫(kù)使用事務(wù)。在應(yīng)用程序使用 JTA 控制事務(wù)操作時(shí),需要從 JNDI 上下文中獲取 UserTranscation 和數(shù)據(jù)源。
UserTranscation ut = (UserTranscation) ctx.lookup("UserTranscation");
1-3、Hibernate 事務(wù)
● 基于 JDBC
Transcation 事務(wù)對(duì)象必須從 Session 中獲取,即事務(wù)必須和一個(gè) Session 相關(guān)聯(lián)。
采用 Hibernate 內(nèi)置的 current session 和上下文管理。
<property name="current_session_context_class">thread</property>
...
sessionFactory.getCurrentSession().beginTranscation();
● 基于 JTA
提供了跨 Session 的事務(wù)管理能力。
使用 SessionFactory.getCurrentSession() 方法簡(jiǎn)化事務(wù)上下文的傳播,即在事務(wù)綁定 Session。
雖然一個(gè) Session 范圍內(nèi)可以存在多個(gè)事務(wù)操作,但是 Hibernate 并不支持嵌套的事務(wù)模型。
tx1
tx2
...
tx2.commit();
//數(shù)據(jù)庫(kù)操作,操作無(wú)效
tx1.commit();
2、并發(fā)控制
如果事務(wù)都是串行執(zhí)行,則許多資源將處于空閑狀態(tài)。為了充分利用資源,發(fā)揮數(shù)據(jù)庫(kù)共享資源的優(yōu)勢(shì),必須允許多個(gè)事務(wù)并發(fā)地執(zhí)行。
在單處理機(jī)系統(tǒng)中,事務(wù)并發(fā)執(zhí)行實(shí)際上是這些并行事務(wù)輪流交叉執(zhí)行,即交叉并發(fā)方式,并不是真正的并行執(zhí)行。在多處理機(jī)系統(tǒng)中,每個(gè)處理機(jī)運(yùn)行一個(gè)事務(wù),實(shí)現(xiàn)事務(wù)真正意義上的并存運(yùn)行,即同時(shí)并發(fā)方式。
當(dāng)多個(gè)用戶并發(fā)地存取數(shù)據(jù)庫(kù)時(shí),就會(huì)產(chǎn)生多個(gè)事務(wù)同時(shí)存取同一數(shù)據(jù)的情況。所以,必須實(shí)現(xiàn)一個(gè)控制系統(tǒng),使一個(gè)事務(wù)所做的修改不會(huì)對(duì)其他事務(wù)所做的修改產(chǎn)生負(fù)面影響,這就是并發(fā)控制。
2-1、封鎖
對(duì)并發(fā)操作進(jìn)行的正確調(diào)度,防止并發(fā)操作破壞了事務(wù)的隔離性。采用封鎖技術(shù),事務(wù) T 可以向系統(tǒng)發(fā)出請(qǐng)求,對(duì)某個(gè)對(duì)象例如表、記錄加鎖,在事務(wù) T 釋放鎖之前,其他事務(wù)不能更新這些數(shù)據(jù)對(duì)象。
基本的封鎖有:
排他鎖(Exclusive Locks,X 鎖):寫(xiě)鎖或者獨(dú)占鎖。
共享鎖(Share Locks,S 鎖):讀鎖。允許和其他事務(wù)一起讀取數(shù)據(jù)對(duì)象D,但不能對(duì)D 做任何修改。
2-2、事務(wù)隔離
使用封鎖技術(shù),事務(wù)對(duì)申請(qǐng)的資源加鎖,但是會(huì)影響數(shù)據(jù)庫(kù)性能。根據(jù)數(shù)據(jù)對(duì)象封鎖的程度,可以分成多種不同的事務(wù)隔離級(jí)別。
數(shù)據(jù)并發(fā)執(zhí)行時(shí),產(chǎn)生不一致的現(xiàn)象:
丟失更新(Lost Update)
兩個(gè)事務(wù)讀入同一數(shù)據(jù)并修改,然后提交修改,T2 提交的結(jié)果破壞了 T1 提交的結(jié)果,導(dǎo)致 T1 的修改丟失。
② 不可重復(fù)讀
事務(wù)T1 讀取數(shù)據(jù)后,事務(wù)T2 執(zhí)行了同一數(shù)據(jù)的跟新操作,使得事務(wù) T1 無(wú)法再現(xiàn)前一次讀取的結(jié)果。
事務(wù)1 讀取某一數(shù)據(jù)后,事務(wù)2 對(duì)該數(shù)據(jù)作了修改,事務(wù)1 再次讀取時(shí),得到數(shù)據(jù)和前一次不一致。
① 事務(wù)1 讀取某一些記錄后,事務(wù)2 刪除了同一數(shù)據(jù)源的部分?jǐn)?shù)據(jù),事務(wù)1 再次讀取時(shí),發(fā)現(xiàn)某些記錄丟失。
① 事務(wù)1 讀取某一些記錄后,事務(wù)2 插入了同一數(shù)據(jù)源的新數(shù)據(jù),事務(wù)1 再次讀取時(shí),發(fā)現(xiàn)某些記錄增加。
③ 讀“臟”數(shù)據(jù)
事務(wù)T1 修改某一數(shù)據(jù),并將其寫(xiě)回物理數(shù)據(jù)庫(kù)。事務(wù)T2 讀取同一數(shù)據(jù)后,事務(wù)T1 由于某種原因被撤銷(xiāo),數(shù)據(jù)庫(kù)將已經(jīng)修改的數(shù)據(jù)恢復(fù)原值,導(dǎo)致事務(wù)T2 保持的數(shù)據(jù)和數(shù)據(jù)庫(kù)中的數(shù)據(jù)產(chǎn)生了不一致。
ANSI SQL-99 標(biāo)準(zhǔn)定義了下列隔離級(jí)別:
● 未提交讀(Read Uncommitted):隔離事務(wù)的最低級(jí)別,只能保證不會(huì)讀取到物理上損壞的數(shù)據(jù)。H:1;允許產(chǎn)生:①②③
● 已提交讀(Read Committed):常見(jiàn)數(shù)據(jù)庫(kù)引擎的默認(rèn)級(jí)別,保證一個(gè)事務(wù)不會(huì)讀取到另一個(gè)事務(wù)已修改但未提交的數(shù)據(jù)。H:2;允許產(chǎn)生:①②
● 可重復(fù)讀(Repeatable Read):保證一個(gè)事務(wù)不能更新已經(jīng)由另一個(gè)事務(wù)讀取但是未提交的數(shù)據(jù)。相當(dāng)于應(yīng)用中的已提交讀和樂(lè)觀并發(fā)控制。H:4;允許產(chǎn)生:①
● 可串行化(Serializable):隔離事務(wù)的最高級(jí)別,事務(wù)之間完全隔離。系統(tǒng)開(kāi)銷(xiāo)最大。H:8;允許產(chǎn)生:
在數(shù)據(jù)庫(kù)中,可以手工設(shè)置事務(wù)的隔離級(jí)別。
Hibernate 在配置文件中聲明事務(wù)的隔離級(jí)別,Hibenate 獲取數(shù)據(jù)庫(kù)連接后,將根據(jù)隔離級(jí)別自動(dòng)設(shè)置數(shù)據(jù)庫(kù)連接為指定的事務(wù)隔離級(jí)別。
<property name="connection.isolation">8</property>
2-3、并發(fā)控制類型
根據(jù)使用的鎖定策略和隔離等級(jí),可以把事務(wù)的并發(fā)控制分為兩種:
① 悲觀并發(fā)控制
用戶使用時(shí)鎖定數(shù)據(jù)。主要應(yīng)用于數(shù)據(jù)爭(zhēng)用激烈的環(huán)境中,以及發(fā)生并發(fā)沖突時(shí)用鎖保護(hù)數(shù)據(jù)的成本低于回滾事務(wù)成本的環(huán)境中。
Hibernate 的悲觀鎖定不在內(nèi)存中鎖定數(shù)據(jù),由底層數(shù)據(jù)庫(kù)負(fù)責(zé)完成。
② 樂(lè)觀并發(fā)控制
用戶讀取數(shù)據(jù)時(shí)不鎖定數(shù)據(jù)。當(dāng)一個(gè)用戶更新數(shù)據(jù)時(shí),系統(tǒng)將進(jìn)行檢查該用戶讀取數(shù)據(jù)后其他用戶是否更改了該數(shù)據(jù),是則產(chǎn)生一個(gè)錯(cuò)誤,一般情況下,收到錯(cuò)誤信息的用戶將回滾事務(wù)并重新開(kāi)始。主要用戶數(shù)據(jù)爭(zhēng)用不大,且偶爾回滾事務(wù)的成本低于讀取數(shù)據(jù)時(shí)鎖定數(shù)據(jù)的成本的環(huán)境中。
Hibernate 中使用元素 version 和 timestamp 實(shí)現(xiàn)樂(lè)觀并發(fā)控制模式的版本控制,并提供多種編程方式。版本是數(shù)據(jù)庫(kù)表中的一個(gè)字段,可以是一個(gè)遞增的整數(shù),也可以是一個(gè)時(shí)間戳,它們對(duì)應(yīng) Java 持久化類的一個(gè)屬性。事務(wù)提交成功后,Hibernate 自動(dòng)修改版本號(hào)。如果另外一個(gè)事務(wù)同時(shí)訪問(wèn)同一數(shù)據(jù),若發(fā)現(xiàn)提交前的版本號(hào)和事前載入的版本號(hào)有出入,則認(rèn)為發(fā)生了沖突,事務(wù)停止執(zhí)行,撤銷(xiāo)操作,并拋出異常。應(yīng)用程序必須捕捉該異常并做出一定的處理。
⒈應(yīng)用程序級(jí)別的版本控制
⒉長(zhǎng)生命周期會(huì)話的自動(dòng)化版本控制
⒊托管對(duì)象的自動(dòng)化版本控制
⒋定制自動(dòng)化版本控制
3、Hibernate 緩存
Hibernate 提供兩級(jí)緩存架構(gòu),第一級(jí)緩存是 Session 內(nèi)的緩存,第二級(jí)緩存是一個(gè)可插拔的緩存,能夠借助第三方的組件實(shí)現(xiàn)。如果應(yīng)用程序中經(jīng)常使用同樣的條件查詢數(shù)據(jù),還可以使用查詢緩存來(lái)提高查詢效率。
針對(duì)緩存的范圍,可以將 Hibernate 持久層緩存分為三個(gè)層次:
① 事務(wù)級(jí)緩存
緩存只能被當(dāng)前事務(wù)訪問(wèn)。緩存的生命周期以來(lái)與事務(wù)的生命周期。事務(wù)緩存由 Session 實(shí)現(xiàn)。一個(gè) Session 的緩存的內(nèi)容只有在本 Session 實(shí)例范圍內(nèi)可用。
② 應(yīng)用級(jí)緩存
緩存在某個(gè)應(yīng)用范圍內(nèi)被所有事務(wù)共享。緩存的生命周期依賴于應(yīng)用程序的生命周期。應(yīng)用級(jí)緩存由 SessionFactory 實(shí)現(xiàn),Session 實(shí)例由其創(chuàng)建,并共享其緩存。
③ 分布式緩存
集群環(huán)境中,緩存被一個(gè) JVM 或多個(gè) JVM 的進(jìn)程共享。分布式緩存由多個(gè)應(yīng)用級(jí)的緩存實(shí)例組成,緩存中的數(shù)據(jù)被復(fù)制到集群環(huán)境中的每個(gè) JVM 節(jié)點(diǎn),JVM 間通過(guò)遠(yuǎn)程通信來(lái)保證緩存中數(shù)據(jù)的一致性。
3-1、緩存查詢結(jié)果
經(jīng)常使用同樣的條件查詢數(shù)據(jù),則可使用查詢緩存。查詢緩存需要和二級(jí)緩存聯(lián)合使用,在二級(jí)緩存中,可以專門(mén)為查詢緩存開(kāi)辟一個(gè)命名緩存區(qū)域。查詢緩存啟動(dòng)后將創(chuàng)建兩個(gè)緩存區(qū)域,org.hibernate.cache.StandardQueryCache 實(shí)現(xiàn)保存查詢結(jié)果集;org.hibernate.cache.UpdateTimestampsCache 實(shí)現(xiàn)保存最近更新的查詢表的時(shí)間戳。
<property name="cache.use_query_cache">true</propery>
//使用查詢緩存
query.setCacheable(true);
//給查詢緩存指定特定的命名緩存區(qū)域
query.setCacheRegion("queryCache");
//如果其他進(jìn)程更新了結(jié)果集,強(qiáng)行刷新緩沖區(qū)域
query.setCacheMode(CacheMode.REFRESH);
//刷新某個(gè)或全部的緩存
SessionFactory.evictQueries() 方法
4、高級(jí)特性
4-1、數(shù)據(jù)庫(kù)連接池 ConnectionProvider
J2SE 環(huán)境中使用建議。
4-2、使用數(shù)據(jù)源
Hibernate 中,DatasourceConnectionProvider 實(shí)現(xiàn)了 ConnectionProvider 接口并封裝了數(shù)據(jù)源的獲取方法,充當(dāng)了 Hibernate 和數(shù)據(jù)源間的適配器。
J2EE 環(huán)境中使用建議。
4-3、過(guò)濾數(shù)據(jù)
把公共的數(shù)據(jù)過(guò)濾條件提取出來(lái)。從 Hibernate 3.0 開(kāi)始,可以利用 Hibernate Filter 對(duì)某個(gè)類或集合附加預(yù)先定義的過(guò)濾條件,在查詢時(shí)過(guò)濾指定條件的數(shù)據(jù)。該過(guò)濾器是全局有效的,使用時(shí)候,還可以指定特定參數(shù)。
4-4、批量處理
批量處理引發(fā)異常的根源在于緩存中保存了過(guò)多的持久化實(shí)例而耗盡內(nèi)存。
① 應(yīng)用程序級(jí)別的批處理
指定 Hibernate 處理 SQL 語(yǔ)句時(shí),必須積累到指定數(shù)量后再向數(shù)據(jù)庫(kù)提交操作。
<property name="jdbc.batch_size">20</property>
② 無(wú)狀態(tài) Session(StatelessSession)
StatelessSession 接口沒(méi)有持久化上下文,也不負(fù)責(zé)持久化實(shí)例的生命周期,沒(méi)有一級(jí)緩存,操作也不會(huì)影響到二級(jí)和查詢緩存。
③ 使用 DML 風(fēng)格的 HQL 語(yǔ)句繞過(guò)內(nèi)存直接進(jìn)行數(shù)據(jù)處理
"delete Product p where p.id > :id"
4-4、延遲加載
設(shè)置延遲加載的屬性和集合只能在該實(shí)例依附的 Session 范圍內(nèi)被訪問(wèn),會(huì)話關(guān)閉后,實(shí)例從持久態(tài)轉(zhuǎn)為托管態(tài),再次訪問(wèn)該實(shí)例的一些屬性時(shí)候,有可能會(huì)拋出 LazyInitializationException 異常。
① 屬性延遲加載(大對(duì)象)
② 持久化類延遲加載
③ 集合延遲加載
4-5、數(shù)據(jù)抓取策略(Fetching strategies)
可以在 Hibernate 中設(shè)定相應(yīng)的數(shù)據(jù)抓取策略,減少系統(tǒng)產(chǎn)生的數(shù)據(jù)庫(kù)查詢操作,優(yōu)化系統(tǒng)性能。
在 Hibernate 中,延遲(lazy)定義了一種契約,用來(lái)表示托管狀態(tài)實(shí)例中那些數(shù)據(jù)是有效的,而抓?。╢etch)是用來(lái)調(diào)整 Hibernate 性能的。
4-5、監(jiān)控性能
org.hibernate.stat 包提供的工具類。
5、附錄
5-1、XML 元數(shù)據(jù)
18.2. XML映射元數(shù)據(jù) - Hibernate reference 3.2.0 ga 正式版中文參考手冊(cè)
18.3. 操作XML數(shù)據(jù) (通過(guò)dom4j會(huì)話讀入和更新應(yīng)用程序中的XML文檔)
5-2、開(kāi)源工具箱
CownewStudio 是一個(gè)基于 Eclipse 的 Hibernate 正向建模輔助工具。通過(guò)它用戶能以圖形化的方式建立對(duì)象模型,然后根據(jù)模型生成持久化類、映射文件和數(shù)據(jù)庫(kù)表。
JDBMonitor。模擬一個(gè) JDBC 驅(qū)動(dòng)來(lái)代替真正的 JDBC 驅(qū)動(dòng),截取應(yīng)用程序?qū)?shù)據(jù)庫(kù)的操作,并以合適的方式記錄下來(lái),提供性能分析的來(lái)源和依據(jù)。
posted on 2009-04-14 09:56
黃小二 閱讀(748)
評(píng)論(0) 編輯 收藏 所屬分類:
S/S2SH 、
J2EE 、
J2SE