J2EE事務(wù)并發(fā)控制策略知識(shí)點(diǎn)有哪些

本文小編為大家詳細(xì)介紹“J2EE事務(wù)并發(fā)控制策略知識(shí)點(diǎn)有哪些”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“J2EE事務(wù)并發(fā)控制策略知識(shí)點(diǎn)有哪些”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

創(chuàng)新互聯(lián)專注于阿城網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供阿城營(yíng)銷型網(wǎng)站建設(shè),阿城網(wǎng)站制作、阿城網(wǎng)頁(yè)設(shè)計(jì)、阿城網(wǎng)站官網(wǎng)定制、微信小程序定制開發(fā)服務(wù),打造阿城網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供阿城網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。

事務(wù)并發(fā)訪問(wèn)控制策略

當(dāng)前J2EE項(xiàng)目中,面臨的一個(gè)共同問(wèn)題就是如果控制事務(wù)的并發(fā)訪問(wèn),雖然有些持久層框架已經(jīng)為我們做了很多工作,但是理解原理,對(duì)于我們開發(fā)來(lái)說(shuō)還是很有用處的。

事務(wù)并發(fā)訪問(wèn)主要可以分為兩類,分別是同一個(gè)系統(tǒng)事務(wù)和跨事務(wù)訪問(wèn)的并發(fā)訪問(wèn)控制,其中同一個(gè)系統(tǒng)事務(wù)可以采取樂(lè)觀鎖以及悲觀鎖策略,而跨多個(gè)系統(tǒng)事務(wù)時(shí)則需要樂(lè)觀離線鎖和悲觀離線鎖。在討論這四種并發(fā)訪問(wèn)控制策略之前,先需要明確一下數(shù)據(jù)庫(kù)事務(wù)隔離級(jí)別的問(wèn)題,ANSI標(biāo)準(zhǔn)規(guī)定了四個(gè)數(shù)據(jù)庫(kù)事務(wù)隔離級(jí)別,它們分別是:

讀取未提交(Read Uncommitted)

這是***的事務(wù)隔離級(jí)別,讀事務(wù)不會(huì)阻塞讀事務(wù)和寫事務(wù),寫事務(wù)也不會(huì)阻塞讀事務(wù),但是會(huì)阻塞寫事務(wù)。這樣造成的一個(gè)結(jié)果就是當(dāng)一個(gè)寫事務(wù)沒有提交的時(shí)候,讀事務(wù)照樣可以讀取,那么造成了臟讀的現(xiàn)象。

讀取已提交(Read Committed)

采用此種隔離界別的時(shí)候,寫事務(wù)就會(huì)阻塞讀事務(wù)和寫事務(wù),但是讀事務(wù)不會(huì)阻塞讀事務(wù)和寫事務(wù),這樣因?yàn)閷懯聞?wù)會(huì)阻塞讀取事務(wù),那么從而讀取事務(wù)就不能讀到臟數(shù)據(jù),但是因?yàn)樽x事務(wù)不會(huì)阻塞其它的事務(wù),這樣還是會(huì)造成不可重復(fù)讀的問(wèn)題。

可重復(fù)讀(Repeatable Read)

采用此種隔離級(jí)別,讀事務(wù)會(huì)阻塞寫事務(wù),但是讀事務(wù)不會(huì)阻塞讀事務(wù),但是寫事務(wù)會(huì)阻塞寫事務(wù)和讀事務(wù)。因?yàn)樽x事務(wù)阻塞了寫事務(wù),這樣以來(lái)就不會(huì)造成不可重復(fù)讀的問(wèn)題,但是這樣還是不能避免幻影讀問(wèn)題。

序列化(serializable)

此種隔離級(jí)別是最嚴(yán)格的隔離級(jí)別,如果設(shè)置成這個(gè)級(jí)別,那么就不會(huì)出現(xiàn)以上所有的問(wèn)題(臟讀,不可重復(fù)讀,幻影讀)。但是這樣以來(lái)會(huì)極大的影響到我們系統(tǒng)的性能,因此我們應(yīng)該避免設(shè)置成為這種隔離級(jí)別,相反的,我們應(yīng)該采用較低的隔離界別,然后再采用并發(fā)控制策略來(lái)進(jìn)行事務(wù)的并發(fā)訪問(wèn)控制)。

其實(shí)我們也可以把事務(wù)隔離級(jí)別設(shè)置為serializable,這樣就不需要采用并發(fā)控制策略了,數(shù)據(jù)庫(kù)就會(huì)為我們做好一切并發(fā)控制,但是這樣以來(lái)會(huì)嚴(yán)重影響我們系統(tǒng)的伸縮性和性能,所以在實(shí)踐中,我們一般采用讀取已提交或者更低的事務(wù)隔離級(jí)別,配合各種并發(fā)訪問(wèn)控制策略來(lái)達(dá)到并發(fā)事務(wù)控制的目的。下面總結(jié)一下常用的控制策略:

1 樂(lè)觀鎖

樂(lè)觀鎖是在同一個(gè)數(shù)據(jù)庫(kù)事務(wù)中我們常采取的策略,因?yàn)樗苁沟梦覀兊南到y(tǒng)保持高的性能的情況下,提高很好的并發(fā)訪問(wèn)控制。樂(lè)觀鎖,顧名思義就是保持一種樂(lè)觀的態(tài)度,我們認(rèn)為系統(tǒng)中的事務(wù)并發(fā)更新不會(huì)很頻繁,即使沖突了也沒事,大不了重新再來(lái)一次。它的基本思想就是每次提交一個(gè)事務(wù)更新時(shí),我們想看看要修改的東西從上次讀取以后有沒有被其它事務(wù)修改過(guò),如果修改過(guò),那么更新就會(huì)失敗,。

***我們需要明確一個(gè)問(wèn)題,因?yàn)闃?lè)觀鎖其實(shí)并不會(huì)鎖定任何記錄,所以如果我們數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別設(shè)置為讀取已提交或者更低的隔離界別,那么是不能避免不可重復(fù)讀問(wèn)題的(因?yàn)榇藭r(shí)讀事務(wù)不會(huì)阻塞其它事務(wù)),所以采用樂(lè)觀鎖的時(shí)候,系統(tǒng)應(yīng)該要容許不可重復(fù)讀問(wèn)題的出現(xiàn)。

了解了樂(lè)觀鎖的概念以后,那么當(dāng)前我們系統(tǒng)中又是如何來(lái)使用這種策略的呢?一般可以采用以下三種方法:

版本(Version)字段:在我們的實(shí)體中增加一個(gè)版本控制字段,每次事務(wù)更新后就將版本字段的值加1.

時(shí)間戳(timestamps):采取這種策略后,當(dāng)每次要提交更新的時(shí)候就會(huì)將系統(tǒng)當(dāng)前時(shí)間和實(shí)體加載時(shí)的時(shí)間進(jìn)行比較,如果不一致,那么就報(bào)告樂(lè)觀鎖失敗,從而回滾事務(wù)或者重新嘗試提交。采用時(shí)間戳有一些不足,比如在集群環(huán)境下,每個(gè)節(jié)點(diǎn)的時(shí)間同步也許會(huì)成問(wèn)題,并且如果并發(fā)事務(wù)間隔時(shí)間小于當(dāng)前平臺(tái)最小的時(shí)鐘單位,那么就會(huì)發(fā)生覆蓋前一個(gè)事務(wù)結(jié)果的問(wèn)題。因此一般采用版本字段比較好。

基于所有屬性進(jìn)行檢測(cè):采用這種策略的時(shí)候,需要比較每個(gè)字段在讀取以后有沒有被修改過(guò),所以這種策略實(shí)現(xiàn)起來(lái)比較麻煩,要求對(duì)每個(gè)屬性都進(jìn)行比較,如果采用hiernate的話,因?yàn)镠ibernate在一級(jí)緩存中可以進(jìn)行臟檢測(cè),那么可以判斷哪些字段被修改過(guò),從而動(dòng)態(tài)的生成sql語(yǔ)句進(jìn)行更新。

下面再總結(jié)一下如何在JDBC和Hibernate中使用樂(lè)觀鎖:

JDBC中使用樂(lè)觀鎖:如果我們采用JDBC來(lái)實(shí)現(xiàn)持久層的話,那么就可以采用以上將的三種支持樂(lè)觀鎖的策略,在實(shí)體中增加一個(gè)version字段或者一個(gè)Date字段,也可以采用基于所有屬性的策略,下面就采用version字段來(lái)做一演示:

假如系統(tǒng)中有一個(gè)Account的實(shí)體類,我們?cè)贏ccount中多加一個(gè)version字段,那么我們JDBC Sql語(yǔ)句將如下寫:

Select a.version....from Account as a where    (where condition..)
Update Account set version = version+1.....(another field) where version =?...(another  contidition)


這樣以來(lái)我們就可以通過(guò)更新結(jié)果的行數(shù)來(lái)進(jìn)行判斷,如果更新結(jié)果的行數(shù)為0,那么說(shuō)明實(shí)體從加載以來(lái)已經(jīng)被其它事務(wù)更改了,所以就拋出自定義的樂(lè)觀鎖定異常(或者也可以采用Spring封裝的異常體系)。具體實(shí)例如下:

.......
int rowsUpdated = statement.executeUpdate(sql);
If(rowsUpdated= =0){
throws new OptimisticLockingFailureException();
}
........


在使用JDBC API的情況下,我們需要在每個(gè)update語(yǔ)句中,都要進(jìn)行版本字段的更新以及判斷,因此如果稍不小心就會(huì)出現(xiàn)版本字段沒有更新的問(wèn)題,相反當(dāng)前的 ORM框架卻為我們做好了一切,我們僅僅需要做的就是在每個(gè)實(shí)體中都增加version或者是Date字段。

Hibernate中使用樂(lè)觀鎖:如果我們采用Hibernate做為持久層的框架,那么實(shí)現(xiàn)樂(lè)觀鎖將變得非常容易,因?yàn)榭蚣軙?huì)幫我們生成相應(yīng)的sql語(yǔ)句,不僅減少了開發(fā)人員的負(fù)擔(dān),而且不容易出錯(cuò)。下面同樣采用version字段的方式來(lái)總結(jié)一下:
同樣假如系統(tǒng)中有一個(gè)Account的實(shí)體類,我們?cè)贏ccount中多加一個(gè)version字段,

public class Account{
Long id ;
.......
@Version //也可以采用XML文件進(jìn)行配置
Int version
.......

}


這樣以來(lái)每次我們提交事務(wù)時(shí),hibernate內(nèi)部會(huì)生成相應(yīng)的SQL語(yǔ)句將版本字段加1,并且進(jìn)行相應(yīng)的版本檢測(cè),如果檢測(cè)到并發(fā)樂(lè)觀鎖定異常,那么就拋出StaleObjectStateException.

2 悲觀鎖

所謂悲觀鎖,顧名思義就是采用一種悲觀的態(tài)度來(lái)對(duì)待事務(wù)并發(fā)問(wèn)題,我們認(rèn)為系統(tǒng)中的并發(fā)更新會(huì)非常頻繁,并且事務(wù)失敗了以后重來(lái)的開銷很大,這樣以來(lái),我們就需要采用真正意義上的鎖來(lái)進(jìn)行實(shí)現(xiàn)。悲觀鎖的基本思想就是每次一個(gè)事務(wù)讀取某一條記錄后,就會(huì)把這條記錄鎖住,這樣其它的事務(wù)要想更新,必須等以前的事務(wù)提交或者回滾解除鎖。

***我們還是需要明確一個(gè)問(wèn)題,假如我們數(shù)據(jù)庫(kù)事務(wù)的隔離級(jí)別設(shè)置為讀取已提交或者更低,那么通過(guò)悲觀鎖,我們控制了不可重復(fù)讀的問(wèn)題,但是不能避免幻影讀的問(wèn)題(因?yàn)橐氡苊馕覀兙托枰O(shè)置數(shù)據(jù)庫(kù)隔離級(jí)別為Serializable,而一般情況下我們都會(huì)采取讀取已提交或者更低隔離級(jí)別,并配合樂(lè)觀或者悲觀鎖來(lái)實(shí)現(xiàn)并發(fā)控制,所以幻影讀問(wèn)題是不能避免的,如果想避免幻影讀問(wèn)題,那么你只能依靠數(shù)據(jù)庫(kù)的serializable隔離級(jí)別(幸運(yùn)的是幻影讀問(wèn)題一般情況下不嚴(yán)重)。

下面就分別以JDBC和Hibernate來(lái)總結(jié)一下:

JDBC中使用悲觀鎖:在JDBC中使用悲觀鎖,需要使用select for update語(yǔ)句,假如我們系統(tǒng)中有一個(gè)Account的類,我們可以采用如下的方式來(lái)進(jìn)行:

Select * from Account where ...(where condition)..    for update.


當(dāng)使用了for update語(yǔ)句后,每次在讀取或者加載一條記錄的時(shí)候,都會(huì)鎖住被加載的記錄,那么當(dāng)其他事務(wù)如果要更新或者是加載此條記錄就會(huì)因?yàn)椴荒塬@得鎖而阻塞,這樣就避免了不可重復(fù)讀以及臟讀的問(wèn)題,但是其他事務(wù)還是可以插入和刪除記錄,這樣也許同一個(gè)事務(wù)中的兩次讀取會(huì)得到不同的結(jié)果集,但是這不是悲觀鎖鎖造成的問(wèn)題,這是我們數(shù)據(jù)庫(kù)隔離級(jí)別所造成的問(wèn)題。

***還需要注意的一點(diǎn)就是每個(gè)沖突的事務(wù)中,我們必須使用select for update 語(yǔ)句來(lái)進(jìn)行數(shù)據(jù)庫(kù)的訪問(wèn),如果一些事務(wù)沒有使用select for update語(yǔ)句,那么就會(huì)很容易造成錯(cuò)誤,這也是采用JDBC進(jìn)行悲觀控制的缺點(diǎn)。

Hibernate中使用悲觀鎖:相比于JDBC使用悲觀鎖來(lái)說(shuō),在Hibernate中使用悲觀鎖將會(huì)容易很多,因?yàn)镠ibernate有API讓我們來(lái)調(diào)用,從而避免直接寫SQL語(yǔ)句。下面就Hibernate使用悲觀鎖做一總結(jié):

首先先要明確一下Hibernate中支持悲觀鎖的兩種模式LockMode.UPGRADE以LockMode.UPGRADE_NO_WAIT.(PS:在JPA中,對(duì)應(yīng)的鎖模式是LockModeType.Read,這與Hibernate是不一樣的呵呵)
假如我們系統(tǒng)中有一個(gè)Account的類,那么具體的操作可以像這樣:

.......
session.lock(account, LockMode.UPGRADE);
......

或者也可以采用如下方式來(lái)加載對(duì)象:
session.get(Account.class,identity,LockMode.UPGRADE).


這樣以來(lái)當(dāng)加載對(duì)象時(shí),hibernate內(nèi)部會(huì)生成相應(yīng)的select for update語(yǔ)句來(lái)加載對(duì)象,從而鎖定對(duì)應(yīng)的記錄,避免其它事務(wù)并發(fā)更新。

讀到這里,這篇“J2EE事務(wù)并發(fā)控制策略知識(shí)點(diǎn)有哪些”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

標(biāo)題名稱:J2EE事務(wù)并發(fā)控制策略知識(shí)點(diǎn)有哪些
當(dāng)前路徑:http://muchs.cn/article32/gdegpc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、網(wǎng)站策劃、云服務(wù)器響應(yīng)式網(wǎng)站、網(wǎng)站收錄、自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)