亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

Hibernate的事務(wù)和并發(fā)

2019-11-18 13:55:23
字體:
供稿:網(wǎng)友
Hibernate的事務(wù)和并發(fā)控制很輕易把握。Hibernate直接使用JDBC連接和JTA資源,不添加任何附加鎖定 行為。我們強(qiáng)烈推薦你花點時間了解JDBC編程,ANSI SQL查詢語言和你使用 的數(shù)據(jù)庫系統(tǒng)的事務(wù)隔離規(guī)范。Hibernate只添加自動版本治理,而不會鎖 定內(nèi)存中的對象,也不會改變數(shù)據(jù)庫事務(wù)的隔離級別?;旧?,使用 Hibernate就似乎直接使用JDBC(或者JTA/CMT)來訪問你的數(shù)據(jù)庫資源。





 除了自動版本治理,針對行級悲觀鎖定,Hibernate也提供了輔助的API,它使用了 SELECT FOR UPDATE的SQL語法。本章后面會討論這個API。
我們從Configuration層、sessionFactory層, 和 Session層開始討論Hibernate的并行控制、數(shù)據(jù)庫事務(wù)和應(yīng)用 程序的長事務(wù)。

12.1.Session和事務(wù)范圍(transaction scopes)
一個SessionFactory對象的創(chuàng)建代價很昂貴,它是線程安全的對象,它被設(shè)計成可以 為所有的應(yīng)用程序線程所共享。它只創(chuàng)建一次,通常是在應(yīng)用程序啟動的時候,由一個 Configuraion的實例來創(chuàng)建。
一個Session的對象是輕型的,非線程安全的,對于單個業(yè)務(wù)進(jìn)程,單個的 工作單元而言,它只被使用一次,然后就丟棄。只有在需要的時候,Session 才會獲取一個JDBC的Connection(或一個Datasource) 對象。所以你可以放心的打開和關(guān)閉Session,甚至當(dāng)你并不確定一個特定的請 求是否需要數(shù)據(jù)訪問時,你也可以這樣做。(一旦你實現(xiàn)下面提到的使用了請求攔截的模式,這就 變得很重要了。
此外我們還要考慮數(shù)據(jù)庫事務(wù)。數(shù)據(jù)庫事務(wù)應(yīng)該盡可能的短,降低數(shù)據(jù)庫鎖定造成的資源爭用。 數(shù)據(jù)庫長事務(wù)會導(dǎo)致你的應(yīng)用程序無法擴(kuò)展到高的并發(fā)負(fù)載。
一個操作單元(Unit of work)的范圍是多大?單個的Hibernate Session能跨越多個 數(shù)據(jù)庫事務(wù)嗎?還是一個Session的作用范圍對應(yīng)一個數(shù)據(jù)庫事務(wù)的范圍?應(yīng)該何時打開 Session,何時關(guān)閉Session?,你又如何劃分?jǐn)?shù)據(jù)庫事務(wù)的邊界呢?

12.1.1.操作單元(Unit of work)
首先,別再用session-per-Operation這種反模式了,也就是說,在單個線程中, 不要因為一次簡單的數(shù)據(jù)庫調(diào)用,就打開和關(guān)閉一次Session!數(shù)據(jù)庫事務(wù)也是如此。 應(yīng)用程序中的數(shù)據(jù)庫調(diào)用是按照計劃好的次序,分組為原子的操作單元。(注重,這也意味著,應(yīng)用程 序中,在單個的SQL語句發(fā)送之后,自動事務(wù)提交(auto-commit)模式失效了。這種模式專門為SQL控制臺操作設(shè)計的。 Hibernate禁止立即自動事務(wù)提交模式,或者期望應(yīng)用服務(wù)器禁止立即自動事務(wù)提交模式。)
在多用戶的client/server應(yīng)用程序中,最常用的模式是 每個請求一個會話(session-per-request)。 在這種模式下,來自客戶端的請求被發(fā)送到服務(wù)器端(即Hibernate持久化層運行的地方),一 個新的Hibernate Session被打開,并且執(zhí)行這個操作單元中所有的數(shù)據(jù)庫操作。 一旦操作完成(同時發(fā)送到客戶端的響應(yīng)也預(yù)備就緒),session被同步,然后關(guān)閉。你也可以使用單 個數(shù)據(jù)庫事務(wù)來處理客戶端請求,在你打開Session之后啟動事務(wù),在你關(guān)閉 Session之前提交事務(wù)。會話和請求之間的關(guān)系是一對一的關(guān)系,這種模式對 于大多數(shù)應(yīng)用程序來說是很棒的。
真正的挑戰(zhàn)在于如何去實現(xiàn)這種模式:不僅Session和事務(wù)必須被正確的開始和結(jié)束, 而且他們也必須能被數(shù)據(jù)訪問操作訪問。用攔截器來實現(xiàn)操作單元的劃分,該攔截器在客戶端請求達(dá)到服 務(wù)器端的時候開始,在服務(wù)器端發(fā)送響應(yīng)(即,ServletFilter)之前結(jié)束。我們推薦 使用一個ThreadLocal 變量,把 Session綁定到處理客戶端請求的線 程上去。這種方式可以讓運行在該線程上的所有程序代碼輕松的訪問Session(就像訪問一 個靜態(tài)變量那樣)。你也可以在一個ThreadLocal 變量中保持事務(wù)上下文環(huán)境,不過這依靠 于你所選擇的數(shù)據(jù)庫事務(wù)劃分機(jī)制。這種實現(xiàn)模式被稱之為 ThreadLocal Session和 Open Session in View。你可以很輕易的擴(kuò)展本文前面章節(jié)展示的 HibernateUtil 輔助類來實現(xiàn)這種模式。當(dāng)然,你必須找到一種實現(xiàn)攔截器的方法,并 且可以把攔截器集成到你的應(yīng)用環(huán)境中。請參考Hibernate網(wǎng)站上面的提示和例子。

12.1.2.應(yīng)用程序事務(wù)(application transactions)
session-per-request模式不僅僅是一個可以用來設(shè)計操作單元的有用概念。很多業(yè)務(wù)處理流程都需 要一系列完整的和用戶之間的交互,即用戶對數(shù)據(jù)庫的交叉訪問。在基于web的應(yīng)用和企業(yè) 應(yīng)用中,跨用戶交互的數(shù)據(jù)庫事務(wù)是無法接受的??紤]下面的例子:
在界面的第一屏,打開對話框,用戶所看到的數(shù)據(jù)是被一個特定的 Session 和數(shù)據(jù) 庫事務(wù)載入(load)的。用戶可以隨意修改對話框中的數(shù)據(jù)對象。
5分鐘后,用戶點擊“保存”,期望所做出的修改被持久化;同時他也期望自己是唯一修改這個信息的人,不會出現(xiàn) 修改沖突。
從用戶的角度來看,我們把這個操作單元稱為應(yīng)用程序長事務(wù)(application transaction)。 在你的應(yīng)用程序中,可以有很多種方法來實現(xiàn)它。
頭一個幼稚的做法是,在用戶思考的過程中,保持Session和數(shù)據(jù)庫事務(wù)是打開的, 保持?jǐn)?shù)據(jù)庫鎖定,以阻止并發(fā)修改,從而保證數(shù)據(jù)庫事務(wù)隔離級別和原子操作。這種方式當(dāng)然是一個反模式, 因為數(shù)據(jù)庫鎖定的維持會導(dǎo)致應(yīng)用程序無法擴(kuò)展并發(fā)用戶的數(shù)目。
很明顯,我們必須使用多個數(shù)據(jù)庫事務(wù)來實現(xiàn)一個應(yīng)用程序事務(wù)。在這個例子中,維護(hù)業(yè)務(wù)處理流程的 事務(wù)隔離變成了應(yīng)用程序?qū)拥牟糠重?zé)任。單個應(yīng)用程序事務(wù)通??缭蕉鄠€數(shù)據(jù)庫事務(wù)。假如僅僅只有一 個數(shù)據(jù)庫事務(wù)(最后的那個事務(wù))保存更新過的數(shù)據(jù),而所有其他事務(wù)只是單純的讀取數(shù)據(jù)(例如在一 個跨越多個請求/響應(yīng)周期的向?qū)эL(fēng)格的對話框中),那么應(yīng)用程序事務(wù)將保證其原子性。這種方式比聽 起來還要輕易實現(xiàn),非凡是當(dāng)你使用了Hibernate的下述特性的時候:
自動版本化 - Hibernate能夠自動進(jìn)行樂觀并發(fā)控制 ,假如在用戶思考 的過程中發(fā)生并發(fā)修改沖突,Hibernate能夠自動檢測到。
脫管對象(Detached Objects)- 假如你決定采用前面已經(jīng)討論過的 session-per-request模式,所有載入的實例在用戶思考的過程 中都處于與Session脫離的狀態(tài)。Hibernate答應(yīng)你把與Session脫離的對象重新關(guān)聯(lián)到Session 上,并且對修改進(jìn)行持久化,這種模式被稱為 session-per-request-with-detached-objects。自動版本化被用來隔離并發(fā)修改。
長生命周期的Session (Long Session)- Hibernate 的Session 可以在數(shù)據(jù)庫事務(wù)提交之后和底層的JDBC連接斷開,當(dāng)一個新的客戶端請求到來的時候,它又重新連接上底層的 JDBC連接。這種模式被稱之為session-per-application-transaction,這種情況可 能會造成不必要的Session和JDBC連接的重新關(guān)聯(lián)。自動版本化被用來隔離并發(fā)修改。
session-per-request-with-detached-objects 和 session-per-application-transaction 各有優(yōu)缺點,我們在本章后面樂觀并發(fā) 控制那部分再進(jìn)行討論。

12.1.3.關(guān)注對象標(biāo)識(Considering object identity)
應(yīng)用程序可能在兩個不同的Session中并發(fā)訪問同一持久化狀態(tài),但是, 一個持久化類的實例無法在兩個 Session中共享。因此有兩種不同的標(biāo)識語義:
數(shù)據(jù)庫標(biāo)識
foo.getId().equals( bar.getId() )
JVM 標(biāo)識
foo==bar
對于那些關(guān)聯(lián)到 特定Session (也就是在單個Session的范圍內(nèi))上的對象來說,這 兩種標(biāo)識的語義是等價的,與數(shù)據(jù)庫標(biāo)識對應(yīng)的JVM標(biāo)識是由Hibernate來保 證的。不過,當(dāng)應(yīng)用程序在兩個不同的session中并發(fā)訪問具有同一持久化標(biāo) 識的業(yè)務(wù)對象實例的時候,這個業(yè)務(wù)對象的兩個實例事實上是不相同的(從 JVM識別來看)。這種沖突可以通過在同步和提交的時候使用自動版本化和樂 觀鎖定方法來解決。
這種方式把關(guān)于并發(fā)的頭疼問題留給了Hibernate和數(shù)據(jù)庫;由于在單個線程內(nèi),操作單元中的對象識別不 需要代價昂貴的鎖定或其他意義上的同步,因此它同時可以提供最好的可伸縮性。只要在單個線程只持有一個 Session,應(yīng)用程序就不需要同步任何業(yè)務(wù)對象。在Session 的范圍內(nèi),應(yīng)用程序可以放心的使用==進(jìn)行對象比較。
不過,應(yīng)用程序在Session的外面使用==進(jìn)行對象比較可能會 導(dǎo)致無法預(yù)期的結(jié)果。在一些無法預(yù)料的場合,例如,假如你把兩個脫管對象實例放進(jìn)同一個 Set的時候,就可能發(fā)生。這兩個對象實例可能有同一個數(shù)據(jù)庫標(biāo)識(也就是說, 他們代表了表的同一行數(shù)據(jù)),從JVM標(biāo)識的定義上來說,對脫管的對象而言,Hibernate無法保證他們 的的JVM標(biāo)識一致。開發(fā)人員必須覆蓋持久化類的equals()方法和 hashCode() 方法,從而實現(xiàn)自定義的對象相等語義。警告:不要使用數(shù)據(jù)庫標(biāo)識 來實現(xiàn)對象相等,應(yīng)該使用業(yè)務(wù)鍵值,由唯一的,通常不變的屬性組成。當(dāng)一個瞬時對象被持久化的時 候,它的數(shù)據(jù)庫標(biāo)識會發(fā)生改變。假如一個瞬時對象(通常也包括脫管對象實例)被放入一 個Set,改變它的hashcode會導(dǎo)致與這個Set的關(guān)系中斷。雖 然業(yè)務(wù)鍵值的屬性不象數(shù)據(jù)庫主鍵那樣穩(wěn)定不變,但是你只需要保證在同一個Set 中的對象屬性的穩(wěn)定性就足夠了。請到Hibernate網(wǎng)站去尋求這個問題更多的具體的討論。請注重,這不是一 個有關(guān)Hibernate的問題,而僅僅是一個關(guān)于java對象標(biāo)識和判等行為如何實現(xiàn)的問題。

12.1.4.常見問題
決不要使用反模式session-per-user-session或者 session-per-application(當(dāng)然,這個規(guī)定幾乎沒有例外)。請注重, 下述一些問題可能也會出現(xiàn)在我們推薦的模式中,在你作出某個設(shè)計決定之前,請務(wù)必理解該模式的應(yīng)用前提。
Session 是一個非線程安全的類。假如一個Session 實例答應(yīng)共享的話,那些支持并發(fā)運行的東東,例如HTTP request,session beans,或者是 Swing workers,將會導(dǎo)致出現(xiàn)資源爭用(race condition)。假如在HttpSession中有 Hibernate 的Session的話(稍后討論),你應(yīng)該考慮同步訪問你的Http session。 否則,只要用戶足夠快的點擊瀏覽器的“刷新”,就會導(dǎo)致兩個并發(fā)運行線程使用同一個 Session。
一個由Hibernate拋出的異常意味著你必須立即回滾數(shù)據(jù)庫事務(wù),并立即關(guān)閉Session (稍后會展開討論)。假如你的Session綁定到一個應(yīng)用程序上,你必 須停止該應(yīng)用程序。回滾數(shù)據(jù)庫事務(wù)并不會把你的業(yè)務(wù)對象退回到事務(wù)啟動時候的狀態(tài)。這 意味著數(shù)據(jù)庫狀態(tài)和業(yè)務(wù)對象狀態(tài)不同步。通常情況下,這不是什么問題,因為異常是不可 恢復(fù)的,你必須在回滾之后重新開始執(zhí)行。
Session 緩存了處于持久化狀態(tài)的每個對象(Hibernate會監(jiān)視和檢查臟數(shù)據(jù))。 這意味著,假如你讓Session打開很長一段時間,或是僅僅載入了過多的數(shù)據(jù), Session占用的內(nèi)存會一直增長,直到拋出OutOfMemoryException異常。這個 問題的一個解決方法是調(diào)用clear() 和evict()來治理 Session的緩存,但是假如你需要大批量數(shù)據(jù)操作的話,最好考慮 使用存儲過程。在第14章 批量處理(Batch PRocessing)中有一些解決方案。在用戶會話期間一直保持 Session打開也意味著出現(xiàn)臟數(shù)據(jù)的可能性很高。

12.2.數(shù)據(jù)庫事務(wù)聲明
數(shù)據(jù)庫(或者系統(tǒng))事務(wù)的聲明總是必須的。在數(shù)據(jù)庫事務(wù)之外,就無法和數(shù)據(jù)庫通訊(這可能會讓那些習(xí)慣于 自動提交事務(wù)模式的開發(fā)人員感到迷惑)。永遠(yuǎn)使用清楚的事務(wù)聲明,即使只讀操作也是如此。進(jìn)行 顯式的事務(wù)聲明并不總是需要的,這取決于你的事務(wù)隔離級別和數(shù)據(jù)庫的能力,但不管怎么說,聲明事務(wù)總歸有益無害。
一個Hibernate應(yīng)用程序可以運行在非托管環(huán)境中(也就是獨立運行的應(yīng)用程序,簡單Web應(yīng)用程序, 或者Swing圖形桌面應(yīng)用程序),也可以運行在托管的J2EE環(huán)境中。在一個非托管環(huán)境中,Hibernate 通常自己負(fù)責(zé)治理數(shù)據(jù)庫連接池。應(yīng)用程序開發(fā)人員必須手工設(shè)置事務(wù)聲明,換句話說,就是手工啟 動,提交,或者回滾數(shù)據(jù)庫事務(wù)。一個托管的環(huán)境通常提供了容器治理事務(wù),例如事務(wù)裝配通過可聲 明的方式定義在EJB session beans的部署描述符中。可編程式事務(wù)聲明不再需要,即使是 Session 的同步也可以自動完成。
讓持久層具備可移植性是人們的理想。Hibernate提供了一套稱為Transaction的封裝API, 用來把你的部署環(huán)境中的本地事務(wù)治理系統(tǒng)轉(zhuǎn)換到Hibernate事務(wù)上。這個API是可選的,但是我們強(qiáng)烈 推薦你使用,除非你用CMT session bean。
通常情況下,結(jié)束 Session 包含了四個不同的階段:
同步session(flush,刷出到磁盤)
提交事務(wù)
關(guān)閉session
處理異常
session的同步(flush,刷出)前面已經(jīng)討論過了,我們現(xiàn)在進(jìn)一步考察在托管和非托管環(huán)境下的事務(wù)聲明和異常處理。

12.2.1.非托管環(huán)境
假如Hibernat持久層運行在一個非托管環(huán)境中,數(shù)據(jù)庫連接通常由Hibernate的連接池機(jī)制 來處理。



代碼內(nèi)容
session/transaction處理方式如下所示:
//Non-managed environment idiom
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();

// do some work
...

tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e; // or display error message
}
finally {
sess.close();
}
你不需要顯式flush() Session - 對commit()的調(diào)用會自動觸發(fā)session的同步。
調(diào)用 close() 標(biāo)志session的結(jié)束。 close()方法重要的暗示是,session釋放了JDBC連接。
這段Java代碼是可移植的,可以在非托管環(huán)境和JTA環(huán)境中運行。
你很可能從未在一個標(biāo)準(zhǔn)的應(yīng)用程序的業(yè)務(wù)代碼中見過這樣的用法;致命的(系統(tǒng))異常應(yīng)該總是 在應(yīng)用程序“頂層”被捕捉。換句話說,執(zhí)行Hibernate調(diào)用的代碼(在持久層)和處理 RuntimeException異常的代碼(通常只能清理和退出應(yīng)用程序)應(yīng)該在不同 的應(yīng)用程序邏輯層。這對于你設(shè)計自己的軟件系統(tǒng)來說是一個挑戰(zhàn),只要有可能,你就應(yīng)該使用 J2EE/EJB容器服務(wù)。異常處理將在本章稍后進(jìn)行討論。
請注重,你應(yīng)該選擇 org.hibernate.transaction.JDBCTransactionFactory (這是默認(rèn)選項).

12.2.2.使用JTA
假如你的持久層運行在一個應(yīng)用服務(wù)器中(例如,在EJB session beans的后面),Hibernate獲取 的每個數(shù)據(jù)源連接將自動成為全局JTA事務(wù)的一部分。Hibernate提供了兩種策略進(jìn)行JTA集成。
假如你使用bean治理事務(wù)(BMT),可以通過使用Hibernate的 Transaction API來告訴 應(yīng)用服務(wù)器啟動和結(jié)束BMT事務(wù)。因此,事務(wù)治理代碼和在非托管環(huán)境下是一樣的。




代碼內(nèi)容
// BMT idiom
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();

// do some work
...

tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e; // or display error message
}
finally {
sess.close();
} 在CMT方式下,事務(wù)聲明是在session bean的部署描述符中,而不需要編程。 除非你設(shè)置了屬性hibernate.transaction.flush_before_completion和 hibernate.transaction.auto_close_session為true, 否則你必須自己同步和關(guān)閉Session。Hibernate可以為你自動同步和關(guān)閉 Session。你唯一要做的就是當(dāng)發(fā)生異常時進(jìn)行事務(wù)回滾。幸運的是, 在一個CMT bean中,事務(wù)回滾甚至可以由容器自動進(jìn)行,因為由session bean方法拋出的未處理的 RuntimeException異??梢酝ㄖ萜髟O(shè)置全局事務(wù)回滾。這意味著 在CMT中,你完全無需使用Hibernate的Transaction API 。
請注重,當(dāng)你配置Hibernate事務(wù)工廠的時候,在一個BMT session bean中,你應(yīng)該選擇 org.hibernate.transaction.JTATransactionFactory,在一個 CMT session bean中選擇org.hibernate.transaction.CMTTransactionFactory。 記住,同時也要設(shè)置org.hibernate.transaction.manager_lookup_class。
假如你使用CMT環(huán)境,并且讓容器自動同步和關(guān)閉session,你可能也希望在你代碼的不同部分使用 同一個session。一般來說,在一個非托管環(huán)境中,你可以使用一個ThreadLocal 變量來持有這個session,但是單個EJB方法調(diào)用可能會在不同的線程中執(zhí)行(舉例來說,一個session bean調(diào)用另一個session bean)。假如你不想在應(yīng)用代碼中被傳遞Session對 象實例的問題困擾的話,那么SessionFactory 提供的 getCurrentSession()方法就很適合你,該方法返回一個綁定到JTA事務(wù) 上下文環(huán)境中的session實例。這也是把Hibernate集成到一個應(yīng)用程序中的最簡單的方法!這個“當(dāng) 前的”session總是可以自動同步和自動關(guān)閉(不考慮上述的屬性設(shè)置)。我們的session/transaction 治理代碼減少到如下所示:




代碼內(nèi)容
// CMT idiom
Session sess = factory.getCurrentSession();

// do some work
...
換句話來說,在一個托管環(huán)境下,你要做的所有的事情就是調(diào)用 SessionFactory.getCurrentSession(),然后進(jìn)行你的數(shù)據(jù)訪問,把其余的工作 交給容器來做。事務(wù)在你的session bean的部署描述符中以可聲明的方式來設(shè)置。session的生命周期完全 由Hibernate來治理。
對after_statement連接釋放方式有一個警告。因為JTA規(guī)范的一個很愚蠢的限制,Hibernate不可能自動清理任何未關(guān)閉的ScrollableResults 或者Iterator,它們是由scroll()或iterate()產(chǎn)生的。你must通過在finally塊中,顯式調(diào)用ScrollableResults.close()或者Hibernate.close(Iterator)方法來釋放底層數(shù)據(jù)庫游標(biāo)。(當(dāng)然,大部分程序完全可以很輕易的避免在CMT代碼中出現(xiàn)scroll()或iterate()。)

12.2.3.異常處理
假如 Session 拋出異常 (包括任何SQLException), 你應(yīng)該立即回滾數(shù)據(jù)庫事務(wù),調(diào)用 Session.close() ,丟棄該 Session實例。Session的某些方法可能會導(dǎo)致session 處于不一致的狀態(tài)。所有由Hibernate拋出的異常都視為不可以恢復(fù)的。確保在 finally 代碼塊中調(diào)用close()方法,以關(guān)閉掉 Session。
HibernateException是一個非檢查期異常(這不同于Hibernate老的版本), 它封裝了Hibernate持久層可能出現(xiàn)的大多數(shù)錯誤。我們的觀點是,不應(yīng)該強(qiáng)迫應(yīng)用程序開發(fā)人員 在底層捕捉無法恢復(fù)的異常。在大多數(shù)軟件系統(tǒng)中,非檢查期異常和致命異常都是在相應(yīng)方法調(diào)用 的堆棧的頂層被處理的(也就是說,在軟件上面的邏輯層),并且提供一個錯誤信息給應(yīng)用軟件的用戶 (或者采取其他某些相應(yīng)的操作)。請注重,Hibernate也有可能拋出其他并不屬于 HibernateException的非檢查期異常。這些異常同樣也是無法恢復(fù)的,應(yīng)該 采取某些相應(yīng)的操作去處理。
在和數(shù)據(jù)庫進(jìn)行交互時,Hibernate把捕捉的SQLException封裝為Hibernate的 JDBCException。事實上,Hibernate嘗試把異常轉(zhuǎn)換為更有實際含義 的JDBCException異常的子類。底層的SQLException可以 通過JDBCException.getCause()來得到。Hibernate通過使用關(guān)聯(lián)到 SessionFactory上的SQLExceptionConverter來 把SQLException轉(zhuǎn)換為一個對應(yīng)的JDBCException 異常的子類。默認(rèn)情況下,SQLExceptionConverter可以通過配置dialect 選項指定;此外,也可以使用用戶自定義的實現(xiàn)類(參考javadocs SQLExceptionConverterFactory類來了解詳情)。標(biāo)準(zhǔn)的 JDBCException子類型是:
JDBCConnectionException - 指明底層的JDBC通訊出現(xiàn)錯誤
SQLGrammarException - 指明發(fā)送的SQL語句的語法或者格式錯誤
ConstraintViolationException - 指明某種類型的約束違例錯誤
LockAcquisitionException - 指明了在執(zhí)行請求操作時,獲取 所需的鎖級別時出現(xiàn)的錯誤。
GenericJDBCException - 不屬于任何其他種類的原生異常

12.3.樂觀并發(fā)控制(Optimistic concurrency control)
唯一能夠同時保持高并發(fā)和高可伸縮性的方法就是使用帶版本化的樂觀并發(fā)控制。版本檢查使用版本號、 或者時間戳來檢測更新沖突(并且防止更新丟失)。Hibernate為使用樂觀并發(fā)控制的代碼提供了三種可 能的方法,應(yīng)用程序在編寫這些代碼時,可以采用它們。我們已經(jīng)在前面應(yīng)用程序長事務(wù)那部分展示了 樂觀并發(fā)控制的應(yīng)用場景,此外,在單個數(shù)據(jù)庫事務(wù)范圍內(nèi),版本檢查也提供了防止更新丟失的好處。
12.3.1.應(yīng)用程序級別的版本檢查(Application version checking)
未能充分利用Hibernate功能的實現(xiàn)代碼中,每次和數(shù)據(jù)庫交互都需要一個新的 Session,而且開發(fā)人員必須在顯示數(shù)據(jù)之前從數(shù)據(jù)庫中重 新載入所有的持久化對象實例。這種方式迫使應(yīng)用程序自己實現(xiàn)版本檢查來確保 應(yīng)用程序事務(wù)的隔離,從數(shù)據(jù)訪問的角度來說是最低效的。這種使用方式和 entity EJB最相似。
// foo is an instance loaded by a previous Session
session = factory.openSession();
Transaction t = session.beginTransaction();
int oldVersion = foo.getVersion();
session.load( foo, foo.getKey() ); // load the current state
if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
foo.setProperty("bar");
t.commit();
session.close();
version 屬性使用 來映射,假如對象 是臟數(shù)據(jù),在同步的時候,Hibernate會自動增加版本號。
當(dāng)然,假如你的應(yīng)用是在一個低數(shù)據(jù)并發(fā)環(huán)境下,并不需要版本檢查的話,你照樣可以使用 這種方式,只不過跳過版本檢查就是了。在這種情況下,最晚提交生效 (last commit wins)就是你的應(yīng)用程序長事務(wù)的默認(rèn)處理策略。 請記住這種策略可能會讓應(yīng)用軟件的用戶感到困惑,因為他們有可能會碰上更新丟失掉卻沒 有出錯信息,或者需要合并更改沖突的情況。
很明顯,手工進(jìn)行版本檢查只適合于某些軟件規(guī)模非常小的應(yīng)用場景,對于大多數(shù)軟件應(yīng)用場景 來說并不現(xiàn)實。通常情況下,不僅是單個對象實例需要進(jìn)行版本檢查,整個被修改過的關(guān) 聯(lián)對象圖也都需要進(jìn)行版本檢查。作為標(biāo)準(zhǔn)設(shè)計范例,Hibernate使用長生命周期 Session的方式,或者脫管對象實例的方式來提供自動版本檢查。

12.3.2.長生命周期session和自動版本化
單個 Session實例和它所關(guān)聯(lián)的所有持久化對象實例都被用于整個 應(yīng)用程序事務(wù)。Hibernate在同步的時候進(jìn)行對象實例的版本檢查,假如檢測到并發(fā)修 改則拋出異常。由開發(fā)人員來決定是否需要捕捉和處理這個異常(通常的抉擇是給用戶 提供一個合并更改,或者在無臟數(shù)據(jù)情況下重新進(jìn)行業(yè)務(wù)操作的機(jī)會)。
在等待用戶交互的時候, Session 斷開底層的JDBC連接。這種方式 以數(shù)據(jù)庫訪問的角度來說是最高效的方式。應(yīng)用程序不需要關(guān)心版本檢查或脫管對象實例 的重新關(guān)聯(lián),在每個數(shù)據(jù)庫事務(wù)中,應(yīng)用程序也不需要載入讀取對象實例。




代碼內(nèi)容
// foo is an instance loaded earlier by the Session
session.reconnect(); // OBTain a new JDBC connection
Transaction t = session.beginTransaction();
foo.setProperty("bar");
t.commit(); // End database transaction, flushing the change and checking the version
session.disconnect(); // Return JDBC connection
foo 對象始終和載入它的Session相關(guān)聯(lián)。 Session.reconnect()獲取一個新的數(shù)據(jù)庫連接(或者 你可以提供一個),并且繼續(xù)當(dāng)前的session。Session.disconnect() 方法把session與JDBC連接斷開,把數(shù)據(jù)庫連接返回到連接池(除非是你自己提供的數(shù)據(jù) 庫連接)。在Session重新連接上數(shù)據(jù)庫連接之后,你可以對任何可能被其他事務(wù)更新過 的對象調(diào)用Session.lock(),設(shè)置LockMode.READ 鎖定模式,這樣你就可以對那些你不預(yù)備更新的數(shù)據(jù)進(jìn)行強(qiáng)制版本檢查。此外,你并不需要 鎖定那些你預(yù)備更新的數(shù)據(jù)。
假若對disconnect()和reconnect()的顯式調(diào)用發(fā)生得太頻繁了,你可以使用hibernate.connection.release_mode來代替。
假如在用戶思考的過程中,Session因為太大了而不能保存,那么這種模式是有 問題的。舉例來說,一個HttpSession應(yīng)該盡可能的小。由于 Session是一級緩存,并且保持了所有被載入過的對象,因此 我們只應(yīng)該在那些少量的request/response情況下使用這種策略。而且在這種情況下, Session 里面很快就會有臟數(shù)據(jù)出現(xiàn),因此請牢牢記住這一建議。
此外,也請注重,你應(yīng)該讓與數(shù)據(jù)庫連接斷開的Session對持久層保持 關(guān)閉狀態(tài)。換句話說,使用有狀態(tài)的EJB session bean來持有Session, 而不要把它傳遞到web層(甚至把它序列化到一個單獨的層),保存在HttpSession中。

12.3.3.脫管對象(deatched object)和自動版本化
這種方式下,與持久化存儲的每次交互都發(fā)生在一個新的Session中。 然而,同一持久化對象實例可以在多次與數(shù)據(jù)庫的交互中重用。應(yīng)用程序操縱脫管對象實例 的狀態(tài),這個脫管對象實例最初是在另一個Session 中載入的,然后 調(diào)用 Session.update(),Session.saveOrUpdate(), 或者 Session.merge() 來重新關(guān)聯(lián)該對象實例。




代碼內(nèi)容
// foo is an instance loaded by a previous Session
foo.setProperty("bar");
session = factory.openSession();
Transaction t = session.beginTransaction();
session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
t.commit();
session.close();
Hibernate會再一次在同步的時候檢查對象實例的版本,假如發(fā)生更新沖突,就拋出異常。
假如你確信對象沒有被修改過,你也可以調(diào)用lock() 來設(shè)置 LockMode.READ(繞過所有的緩存,執(zhí)行版本檢查),從而取 代 update()操作。

12.3.4.定制自動版本化行為
對于特定的屬性和集合,通過為它們設(shè)置映射屬性optimistic-lock的值 為false,來禁止Hibernate的版本自動增加。這樣的話,假如該屬性 臟數(shù)據(jù),Hibernate將不再增加版本號。
遺留系統(tǒng)的數(shù)據(jù)庫Schema通常是靜態(tài)的,不可修改的?;蛘?,其他應(yīng)用程序也可能訪問同一數(shù)據(jù) 庫,根本無法得知如何處理版本號,甚至?xí)r間戳。在以上的所有場景中,實現(xiàn)版本化不能依靠 數(shù)據(jù)庫表的某個特定列。在的映射中設(shè)置 optimistic-lock="all"可以在沒有版本或者時間戳屬性映射的情況下實現(xiàn) 版本檢查,此時Hibernate將比較一行記錄的每個字段的狀態(tài)。請注重,只有當(dāng)Hibernate能夠比 較新舊狀態(tài)的情況下,這種方式才能生效,也就是說, 你必須使用單個長生命周期Session模式,而不能使用 session-per-request-with-detached-objects模式。
有些情況下,只要更改不發(fā)生交錯,并發(fā)修改也是答應(yīng)的。當(dāng)你在 的映射中設(shè)置optimistic-lock="dirty",Hibernate在同步的時候?qū)⒅槐容^有臟 數(shù)據(jù)的字段。
在以上所有場景中,不管是專門設(shè)置一個版本/時間戳列,還是進(jìn)行全部字段/臟數(shù)據(jù)字段比較, Hibernate都會針對每個實體對象發(fā)送一條UPDATE(帶有相應(yīng)的 WHERE語句 )的SQL語句來執(zhí)行版本檢查和數(shù)據(jù)更新。假如你對關(guān)聯(lián)實體 設(shè)置級聯(lián)關(guān)系使用傳播性持久化(transitive persistence),那么Hibernate可能會執(zhí)行不必 要的update語句。這通常不是個問題,但是數(shù)據(jù)庫里面對on update點火 的觸發(fā)器可能在脫管對象沒有任何更改的情況下被觸發(fā)。因此,你可以在 的映射中,通過設(shè)置select-before-update="true" 來定制這一行為,強(qiáng)制Hibernate SELECT這個對象實例,從而保證, 在更新記錄之前,對象的確是被修改過。

12.4.悲觀鎖定(Pessimistic Locking)
用戶其實并不需要花很多精力去擔(dān)心鎖定策略的問題。通常情況下,只要為JDBC連接指定一下隔 離級別,然后讓數(shù)據(jù)庫去搞定一切就夠了。然而,高級用戶有時候希望進(jìn)行一個排它的悲觀鎖定, 或者在一個新的事務(wù)啟動的時候,重新進(jìn)行鎖定。
Hibernate總是使用數(shù)據(jù)庫的鎖定機(jī)制,從不在內(nèi)存中鎖定對象!
類LockMode 定義了Hibernate所需的不同的鎖定級別。一個鎖定 可以通過以下的機(jī)制來設(shè)置:
當(dāng)Hibernate更新或者插入一行記錄的時候,鎖定級別自動設(shè)置為LockMode.WRITE。
當(dāng)用戶顯式的使用數(shù)據(jù)庫支持的SQL格式SELECT ... FOR UPDATE 發(fā)送SQL的時候,鎖定級別設(shè)置為LockMode.UPGRADE
當(dāng)用戶顯式的使用Oracle數(shù)據(jù)庫的SQL語句SELECT ... FOR UPDATE NOWAIT 的時候,鎖定級別設(shè)置LockMode.UPGRADE_NOWAIT
當(dāng)Hibernate在“可重復(fù)讀”或者是“序列化”數(shù)據(jù)庫隔離級別下讀取數(shù)據(jù)的時候,鎖定模式 自動設(shè)置為LockMode.READ。這種模式也可以通過用戶顯式指定進(jìn)行設(shè)置。
LockMode.NONE 代表無需鎖定。在Transaction結(jié)束時, 所有的對象都切換到該模式上來。與session相關(guān)聯(lián)的對象通過調(diào)用update() 或者saveOrUpdate()脫離該模式。
"顯式的用戶指定"可以通過以下幾種方式之一來表示:
調(diào)用 Session.load()的時候指定鎖定模式(LockMode)。
調(diào)用Session.lock()。
調(diào)用Query.setLockMode()。
假如在UPGRADE或者UPGRADE_NOWAIT鎖定模式下調(diào) 用Session.load(),并且要讀取的對象尚未被session載入過,那么對象 通過SELECT ... FOR UPDATE這樣的SQL語句被載入。假如為一個對象調(diào)用 load()方法時,該對象已經(jīng)在另一個較少限制的鎖定模式下被載入了,那 么Hibernate就對該對象調(diào)用lock() 方法。
假如指定的鎖定模式是READ, UPGRADE 或 UPGRADE_NOWAIT,那么Session.lock()就 執(zhí)行版本號檢查。(在UPGRADE 或者UPGRADE_NOWAIT 鎖定模式下,執(zhí)行SELECT ... FOR UPDATE這樣的SQL語句。)
假如數(shù)據(jù)庫不支持用戶設(shè)置的鎖定模式,Hibernate將使用適當(dāng)?shù)奶娲J剑ǘ皇侨映霎惓#?這一點可以確保應(yīng)用程序的可移植性。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
国产一二三四五区| 男女午夜激烈无遮挡| 男女精品网站| 午夜美女久久久久爽久久| 精品视频在线免费观看| 3atv在线一区二区三区| 直接看的黄色网址| 国产精品午夜剧场| 少妇的滋味中文字幕bd| 久久视频这里只有精品| 四虎成人免费电影| 亚洲一二三区在线| av电影免费看| 樱桃视频成人在线观看| 日本黄色免费录像| 中文字幕第88页| 亚洲欧美日韩直播| 超碰超碰超碰超碰超碰| 欧洲成人一区二区| 国产成人香蕉在线视频网站| 美女网站在线观看| 精品视频免费| 日产午夜精品一线二线三线| 国产91热爆ts人妖在线| 欧美视频一区二区三区| 国产精选在线观看| 国产美女主播视频一区| 国产精品试看| 猛性xxxxx| 欧美激情中文字幕一区二区| 国产无套精品一区二区| 欧美aa一级| yw193.com尤物在线| 国产91精品一区二区绿帽| 国产精品a久久久久| 色婷婷一区二区三区在线观看| 99久久国产综合色|国产精品| 国产大学生校花援交在线播放| 亚洲成人免费在线视频| 日韩中文字幕免费| 国产精品久久久久久影视| 99在线观看视频网站| 美媛馆国产精品一区二区| 国产视频福利| 亚洲日本国产精品| 日韩片在线观看| 91久热免费在线视频| 国产精品精品久久久| 日本中文字幕影院| 狠狠狠色丁香婷婷综合激情| 丝袜熟女一区二区三区| 欧美一级一区二区三区| 青青草视频在线视频| 成人福利小视频| 免费污污视频在线观看| 久久久久噜噜噜亚洲熟女综合| 欧美黑人猛交的在线视频| 亚洲va久久久噜噜噜无码久久| 久久国产香蕉视频| 午夜激情小视频| 日本黄色成人| 爽爽窝窝午夜精品一区二区| 中文字幕无线精品亚洲乱码一区| 国产精品无码一区二区三| 99在线观看免费| 国产成人午夜| 人人妻人人澡人人爽| 秋霞av一区二区三区| 亚洲人成网站77777在线观看| 91手机视频在线| 好吊妞国产欧美日韩免费观看网站| 国产999精品久久| 日韩三级在线观看视频| 天天草天天干| 国产精品久久999| 国产在线美女| 天天躁日日躁狠狠躁av| 亚洲午夜在线观看| 制服丝袜综合网| 91麻豆精品久久久久蜜臀| 最新欧美日韩亚洲| 国产激情在线播放| 精品国产视频在线观看| 亚洲a∨精品一区二区三区导航| 男人日女人下面视频| 亚洲老妇色熟女老太| 国产又粗又黄视频| 欧美电影在线免费观看| 欧美视频三区在线播放| 国产精品自在欧美一区| 欧美激情第6页| 亚洲熟妇无码av| 亚洲欧洲久久久| 成人看片黄a免费看视频| chien国产乱露脸对白| 欧美一级日韩不卡播放免费| 久久99精品一区二区三区三区| 精品视频在线观看一区| 美脚丝袜一区二区三区在线观看| 久久福利视频网| 国产成人精品亚洲男人的天堂| 国产精品网红福利| 黄色在线观看免费| 欧美精品密入口播放| 尤物av一区二区| 韩国三级丰满少妇高潮| 国产精品日韩久久久久| 懂色av影视一区二区三区| 不卡在线视频| 91久久久久久久久久久久| 国产黄色高清在线| 中文字幕在线播放av| 婷婷5月激情5月| 免费亚色电影在线观看| 天天干,天天干| 清纯唯美亚洲综合| 国产男男gay体育生网站| 秋霞午夜电影| 69成人在线| 欧美精品久久久| 久久视频在线免费观看| 亚洲黄色大片| 香蕉视频在线免费| 国产调教视频一区| 三年中国中文在线观看免费播放| 日韩视频免费在线播放| 图片区小说区亚洲| 日韩国产激情| 亚洲电影天堂av| 亚洲黄色在线看| 在线观看欧美亚洲| 欧美日韩你懂的| 中文字幕精品www乱入免费视频| 亚洲最新av在线网站| 国精产品99永久一区一区| 成av人片一区二区| 国产精品被窝福利一区| 综合av第一页| 男人天堂视频在线| 高潮无码精品色欲av午夜福利| 日本不卡视频在线| 国产aaa免费视频| 日韩影片中文字幕| 亚洲精品网站在线观看| 亚洲成人av电影在线| 日本搞黄视频| www在线视频观看| 欧美人与性动交| 欧美1o一11sex性hdhd| 一级免费黄色录像| 黄色片网站在线播放| 中文字幕精品在线视频| wwwwwww色| 日韩欧美成人精品| 91九色最新地址| 亚洲黄网站在线观看| 国产成人91久久精品| 欧美在线观看视频一区二区| 国产精品国产三级国产aⅴ无密码| 亚洲经典一区二区| av电影在线观看网站| 91精品中文字幕| 国产精品人人爱一区二区白浆| 亚洲专区免费| 啦啦啦中文在线观看日本| 久久久久久久色| 国产尤物一区二区在线| 国产精品午夜av在线| 亚洲精品影院在线| 韩日欧美一区二区三区| 91久久视频| 熟妇人妻系列aⅴ无码专区友真希| 亚洲跨种族黑人xxx| 精品亚洲国产成人av制服丝袜| 一本色道久久综合| 久久99精品国产自在现线| 色老头一区二区三区在线观看| 亚洲一区图片| 日本欧美日韩| 亚州av乱码久久精品蜜桃| 99国产精品一区二区| 欧美视频精品全部免费观看| 91久久精品日日躁夜夜躁国产| 91丨精品丨国产| 欧洲美女免费图片一区| 欧美成人日本| 污视频网站入口| 成人深夜直播免费观看| 中文乱码字幕av网站| 国产精品一区二区精品| 国产成人综合网站| www.激情小说.com| 日本aa在线| www精品国产| 亚洲美女福利视频| 欧美freesex交免费视频| 亚洲一区在线日韩在线深爱| 国产一区二区三区网| 成人在线资源网址| 国产老妇另类xxxxx| 欧美电影免费提供在线观看| 日韩成人精品在线观看| 国产伦精品一区二区三区视频网站| 亚洲精品乱码久久久久久蜜桃图片| 国产精品115| 丰满人妻一区二区三区免费视频| 成人h视频在线观看| 在线综合色站| 欧美精品黄色| 最新国产精品久久| 午夜影院在线免费观看| 欧美国产视频日韩| 看成年女人免费午夜视频| 天天av导航| 欧美一区二区三区免费看| 色视频在线免费观看| 偷拍25位美女撒尿视频在线观看| 日韩av在线播放中文字幕| 色影视在线观看| 看黄的a网站| 国产日韩中文字幕| 免费人成网站在线观看欧美高清| 午夜精品久久久内射近拍高清| 影音先锋在线一区| 国产三级在线免费| 亚洲欧洲视频在线观看| 国产精品综合久久| 在线日韩av永久免费观看| www.久久久久爱免| 少妇高潮露脸国语对白| 欧美亚洲成人精品| 91极品在线| 久久久影院免费| 能在线观看av网站| 182在线观看视频| 欧美成年黄网站色视频| 亚洲欧洲美洲国产香蕉| 成人黄色在线观看| 日韩一区二区三区在线观看| 亚洲av成人无码久久精品老人| 午夜国产精品影院在线观看| 色影视在线观看| 人妻互换一二三区激情视频| 男女啪啪免费视频网站| 久久中文字幕av一区二区不卡| 黄色片视频在线观看| 国产精品高清一区二区| 精品国产亚洲一区二区麻豆| 国产麻豆精品久久| 污污视频在线免费| 亚洲欧美三级在线| 古典武侠综合av第一页| 婷婷伊人综合| 91一区二区在线观看| 91午夜精品亚洲一区二区三区| 成人h动漫精品一区二| 六月婷婷一区| 欧美色图中文字幕| 国产一级理论片| 自拍亚洲一区| 天天撸夜夜操| 中文字幕一区二区三区人妻| xxxx18hd亚洲hd捆绑| 热舞福利精品大尺度视频| 性感美女一区二区三区| 黄色三级视频片| 在线成人高清不卡| 日韩国产精品毛片| 丁香综合五月| 成人午夜在线| 欧美艳星kaydenkross| 婷婷激情综合网| chinese偷拍一区二区三区| 亚洲精品视频免费在线观看| 欧美中文娱乐网| av在线影视| 欧美一区激情视频在线观看| 欧美性巨大欧美| 欧美+亚洲+精品+三区| 真人做人试看60分钟免费| 国产传媒久久文化传媒| 全国男人的天堂天堂网| 在线免费看黄色片| 成人国产一区二区三区精品| 蜜桃视频在线观看播放| 你懂的在线看| 久久亚洲精品视频| 三妻四妾完整版在线观看电视剧| 欧美黑人经典片免费观看| 国产拍揄自揄精品视频麻豆| av在线播放资源| 爱搞国产精品| 日本道色综合久久影院| 97久久综合精品久久久综合| 国产乱在线观看完整版视频| 成年女人免费毛片视频永久| 亚洲美女爱爱视频| 国产精品香蕉国产| 猫咪av在线| 制服丝袜中文字幕第一页| 日韩精品人妻中文字幕有码| 国产精品乱子伦| 福利一区视频在线观看| 精品福利视频导航大全| 天天躁日日躁aaaa视频| 91aaa精品| 91精品国产高清91久久久久久| 伊人网在线视频观看| 国产成人av一区二区| 欧美日韩精品免费在线观看视频| 黄色动漫网站| 国产乱码精品一区二区三区亚洲人| 亚洲天堂一区二区在线观看| 亚洲一区日韩| 欧美1区2区3区| 性感小视频在线看免费| 成人mm视频在线观看| 欧美精品久久一区二区三区| 成人在线观看毛片| 中文字幕一区二区三区免费看| 乱中年女人av三区中文字幕| 久久99精品久久久久久琪琪| 欧美日韩视频在线观看一区二区三区| 强制高潮抽搐sm调教高h| 久久久精品动漫| 日韩黄色免费网站| 国产精品一区二区av| 欧美性猛交xx|