自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Web應(yīng)用中并發(fā)控制的實現(xiàn)

開發(fā) 前端
Web應(yīng)用已由原來的網(wǎng)站、電子商務(wù)發(fā)展成商業(yè)應(yīng)用系統(tǒng)的一種架構(gòu)-B/S架構(gòu),它已成為一個世界性的研究熱點。但由于Internet網(wǎng)絡(luò)協(xié)議固有的局限性以及Web應(yīng)用中頻繁的用戶交互增加了在Internet上實現(xiàn)長事務(wù)的困難,從而,Web應(yīng)用中的并發(fā)控制始終沒能得到很好的解決。本文從Hibernate的樂觀鎖和悲觀鎖的實現(xiàn)原理出發(fā),給出了實現(xiàn)悲觀鎖的基本思路和實現(xiàn)時的注意事項,在其它架構(gòu)中得以推廣和應(yīng)用。

引言

B/S構(gòu)架的應(yīng)用越來越普及,但由于它有別于C/S構(gòu)架的特殊性,并發(fā)控制始終沒能得到很好的解決,如售票系統(tǒng)經(jīng)常會出現(xiàn)同一張火車票出售多次的現(xiàn)象。典型的案例如下:

例如若有兩個客戶端,A客戶先讀取了賬戶余額2000元,之后B客戶也讀取了賬戶余額2000元的數(shù)據(jù),A客戶提取了500元,對數(shù)據(jù)庫作了變更,此時數(shù)據(jù)庫中的余額為1500元,B客戶也要提取1300元,根據(jù)其所取得的資料,2000-1300將為700余額,若此時再對數(shù)據(jù)庫進行變更,最后的余額700元就會不正確,應(yīng)當是200元,問題的出現(xiàn)是由于兩個客戶對同一條數(shù)據(jù)進行并發(fā)訪問造成的。

Web應(yīng)用中并發(fā)控制的特殊性

上述問題在C/S構(gòu)架中可以通過長事務(wù)來實現(xiàn),但Web應(yīng)用是基于Internet網(wǎng)絡(luò)環(huán)境的,其中的并發(fā)控制有其內(nèi)在的特殊性:

1. Web所基于的網(wǎng)絡(luò)協(xié)議HTTP(Hyper Text Transfer Protocol)是一種無連接的協(xié)議,數(shù)據(jù)庫服務(wù)器無法保存事務(wù)的狀態(tài)信息;

2. 用戶可以隨時中止或啟動瀏覽器中當前主頁上的事務(wù)。

由于上述特殊性,Web應(yīng)用中并發(fā)控制不能采用嚴格的長事務(wù)來實現(xiàn),但可以長事務(wù)的思路來實現(xiàn),在數(shù)據(jù)讀取的時候把相應(yīng)的數(shù)據(jù)鎖定,在更新階段把鎖放開,然后更新數(shù)據(jù)。

Web應(yīng)用中并發(fā)控制的實現(xiàn)

業(yè)務(wù)邏輯的實現(xiàn)過程中,往往需要保證數(shù)據(jù)訪問的排他性。如在 金融 系統(tǒng)的日終結(jié)算處理中,我們希望針對某個cut-off時間點的數(shù)據(jù)進行處理,而不希望在結(jié)算進行過程中(可能是幾秒種,也可能是幾個小時),數(shù)據(jù)再發(fā)生變化。此時,我們就需要通過一些機制來保證這些數(shù)據(jù)在某個操作過程中不會被外界修改,這樣的機制,就是所謂的“鎖”,即給選定的目標數(shù)據(jù)上鎖,使其無法被其他程序修改。有兩種鎖機制:即通常所說的“樂觀鎖(Optimistic Locking)” 和“悲觀鎖(Pessimistic Locking)”。

1.樂觀鎖(Optimistic Locking)

樂觀鎖(optimistic locking)則樂觀的認為資料的存取很少發(fā)生同時存取的問題,因而不作數(shù)據(jù)庫層次上的鎖定,為了維護正確的數(shù)據(jù),樂觀鎖定使用應(yīng)用程序上的邏輯實現(xiàn)版本控制來解決。

并發(fā)控制時,數(shù)據(jù)不一致的情況一旦發(fā)生,有幾個解決的 方法 ,一種是先更新為主,一種是后更新的為主,比較復(fù)雜的就是檢查發(fā)生變動的數(shù)據(jù)來實現(xiàn),或是檢查所有屬性來實現(xiàn)樂觀鎖定。

Hibernate通過版本號檢查來實現(xiàn)后更新為主,這也是Hibernate所推薦的方式,在數(shù)據(jù)庫中加入一個VERSON欄記錄,在讀取數(shù)據(jù)時連同版本號一同讀取,并在更新數(shù)據(jù)時遞增版本號,然后比對版本號與數(shù)據(jù)庫中的版本號,如果大于數(shù)據(jù)庫中的版本號則予以更新,否則就回報錯誤。

以Hibernate實現(xiàn)版本號控制鎖定的話,我們的對象中增加一個version屬性,例如:

public class MyAccount {
  private int version;
  ....
  public void setVersion(int version) {
    this.version = version;
  }
  public int getVersion() {
    return version;
  }
  ....
}

而在映像文件中,我們使用optimistic-lock屬性設(shè)定version控制,屬性欄之后增加一個標簽,例如:

optimistic-lock="version"

設(shè)定好版本控制之后,在上例中如果B客戶試圖更新數(shù)據(jù),將會引發(fā)StableObjectStateException例外,我們可以捕捉這個例外,在處理中重新讀取數(shù)據(jù)庫中的數(shù)據(jù),同時將B客戶目前的數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)讀出來,讓B客戶有機會比對不一致的數(shù)據(jù),以決定要變更的部份,或者您可以設(shè)計程式自動讀取新的資料,并重復(fù)扣款業(yè)務(wù)流程,直到數(shù)據(jù)可以更新為止,這一切可以在后臺執(zhí)行,而不用讓您的客戶知道。在其它架構(gòu)中也可通過這種思路來實現(xiàn)樂觀鎖,但版本控制和沖突的檢測要在自己程序的程序中實現(xiàn)和維護。

#p#

2.悲觀鎖(Pessimistic Locking)

雖然樂觀鎖能夠提高系統(tǒng)的性能,但它是對發(fā)生沖突的訪問進行事后的補救,應(yīng)用在用戶輸入數(shù)據(jù)量很少的場合比較適合,但如果在 企業(yè) ERP,用戶與系統(tǒng)交互涉及大量數(shù)據(jù)在頁面表單上錄入,如果事后提交失敗后才提示用戶要重新錄入是很不現(xiàn)實的,所以有必要進行事前控制,這就要采用悲觀鎖。

在多個客戶端可能讀取同一筆數(shù)據(jù)或同時更新一筆數(shù)據(jù)的情況下,防止同一個數(shù)據(jù)被修改而造成混亂,最簡單的手段就是在讀取時對數(shù)據(jù)進行鎖定,其它客戶端不能對同一筆數(shù)據(jù)進行更新的讀取動作。

悲觀鎖定(Pessimistic Locking)一如其名稱所示,悲觀的認定每次資料存取時,其它的客戶端也會存取同一筆數(shù)據(jù),因此對該筆數(shù)據(jù)進行事先鎖定,直到自己操作完成后解除鎖定。

悲觀鎖定通常透過系統(tǒng)或數(shù)據(jù)庫本身的功能來實現(xiàn),依賴系統(tǒng)或數(shù)據(jù)庫本身提供的鎖定機制,Hibernate即是如此,我們可以利用Query或Criteria的setLockMode()方法來設(shè)定要鎖定的表或列(row)及其鎖定模式,鎖定模式有以下的幾個:

LockMode.WRITE:在insert或update時進行鎖定,Hibernate會在save()方法時自動獲得鎖定。

LockMode.UPGRADE:利用SELECT … FOR UPDATE進行鎖定。

LockMode.UPGRADE_NOWAIT:利用SELECT … FOR UPDATE NOWAIT進行鎖定,在Oracle環(huán)境下使用。

LockMode.READ:在讀取記錄時Hibernate會自動獲得鎖定。

LockMode.NONE:沒有鎖定。

也可以在使用Session的load()或是lock()時指定鎖定模式以進行鎖定。

如果數(shù)據(jù)庫不支持所指定的鎖定模式,Hibernate會選擇一個合適的鎖定替換,而不是丟出一個例外。

3.其它構(gòu)架中悲觀鎖的實現(xiàn)

Hibernate的悲觀鎖,也是基于數(shù)據(jù)庫的鎖機制實現(xiàn)。下面的代碼實現(xiàn)了對“用戶”查詢記錄的加鎖:

String sqlStr = "from userInfo as user where user.userId=’admin’";
Query query = session.createQuery(sqlStr);
query.setLockMode("user",LockMode.UPGRADE); //加鎖
List userList = query.list();//執(zhí)行查詢,獲取數(shù)據(jù)

query.setLockMode對查詢語句中,特定別名所對應(yīng)的記錄進行加鎖(我們?yōu)閡serInfo類指定了一個別名“user”),這里也就是對返回的所有user記錄進行加鎖:

select tuser0_.id as id, tuser0_.userId as userId, tuser0_.group_id as group_id, 
tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where
(tuser0_.userId =’admin’ ) for update

通過上述轉(zhuǎn)換后的sql語句可知,Hibernate的加鎖其實是利用了數(shù)據(jù)庫的for update語句,在讀取階段對某條記錄的鎖定,而在更新階段提交,釋放鎖。

其實其它架構(gòu)也可以采取該思路,不過,數(shù)據(jù)庫的for update語句的鎖定和釋放一定要在數(shù)據(jù)的同一個連接中,如果讀取階段和更新階段不是統(tǒng)一連接,即讀取之后斷開了與數(shù)據(jù)庫的連接,則for update語句的鎖定立即失效,為此,如果其它架構(gòu)中要采取這種方式則要做相應(yīng)的調(diào)整。

首先,由于Web應(yīng)用是無狀態(tài)的,也就是說數(shù)據(jù)庫的for update語句的鎖定和釋放不一定是數(shù)據(jù)的同一個連接,為此,采用痕跡跟蹤法,在讀取數(shù)據(jù)時生成唯一的序列號(serialId),建立與數(shù)據(jù)連接的映射,并放置一個map數(shù)據(jù)結(jié)構(gòu)中;在更新時,通過該serialId在連接池中重新獲取該連接,用該連接去更新數(shù)據(jù)。

如果系統(tǒng)是采用dao讀取數(shù)據(jù),實體bean去更新數(shù)據(jù),則只要在更新數(shù)據(jù)之前斷開讀取數(shù)據(jù)時的連接,則可以通過其它途徑更新數(shù)據(jù),如下代碼所示:

public void update (AbstractEntityData data, String[] selTeamName ,String serialId) 
throws Exception {
   dao.closeConnect(serialId);
bo.update(data);
}

其中,dao.closeConnect(serialId)是斷開數(shù)據(jù)連接,bo.update(data)是通過EJB更新數(shù)據(jù)庫

4.序列號(serialId)的創(chuàng)建和維護

由于不同用戶可能同時建立連接或同一用戶先后建立連接,故創(chuàng)建序列號可以在讀取數(shù)據(jù)時通過sessionId和時間戳組合而成。而在操作的過程中,為了保持序列號不會丟失和唯一性,它不能放在session或application中,而是放在頁面的request對象里,通過它向其它頁面?zhèn)鬟f。

5.關(guān)聯(lián)表的鎖定

其實,Hibernate的悲觀鎖方式只能對單個表的記錄進行鎖定,但現(xiàn)實中,存在關(guān)聯(lián)更新的情況,即在更新主表的時候有可能會更新到與之相關(guān)的子表,與此同時,其它用戶也可能通過其它主表更新相應(yīng)的子表同一條記錄。

有兩種方式處理,一是在讀取數(shù)據(jù)通過sql語句關(guān)聯(lián)子表相應(yīng)記錄,因為for update對所有關(guān)聯(lián)表中符合條件的記錄都會加鎖;二是為子表找一個入口表,在更新子表的同時,必須更新子表的入口表。

6.例外操作的處理

采用這種方式,有一些例外情況必須小心處理,一是頁面的關(guān)閉,如果調(diào)用相應(yīng)的方法,如onbeforeunload()等,釋放對應(yīng)的數(shù)據(jù)庫連接;二是用戶非正常關(guān)機退出系統(tǒng),必須有數(shù)據(jù)庫周期清除無用的連接,如間隔二十分鐘等,來釋放讀取時對數(shù)據(jù)的鎖定,否則,該數(shù)據(jù)會長時間被鎖定,直至應(yīng)用服務(wù)器重啟。

結(jié)論

軟件系統(tǒng)的并發(fā)控制一般是通過加鎖來實現(xiàn),同樣,Web應(yīng)用也是采用樂觀鎖和悲觀鎖來實現(xiàn),樂觀鎖是一種事后補救措施,是通過程序的邏輯控制版本來實現(xiàn)的,而悲觀鎖是事前的一種預(yù)防措施,它利用數(shù)據(jù)庫的鎖機制來實現(xiàn),Hibernate對它做了一層封裝,使應(yīng)用更加方便,為了讓其它架構(gòu)都能適用,本文還原了Hibernate的實現(xiàn)原理,提出一般的實現(xiàn)思路和注意實現(xiàn)。

【編輯推薦】

  1. AJAX和XmlHttpRequest下的Web開發(fā)
  2. Java和PHP在Web開發(fā)方面的比較
  3. JSF進行Web開發(fā)的三大優(yōu)勢
責(zé)任編輯:楊鵬飛 來源: 中國論文聯(lián)盟
相關(guān)推薦

2021-04-07 06:00:18

JavaScript 前端并發(fā)控制

2010-11-17 19:40:32

PacketShapeBlue Coat

2017-11-06 17:16:55

Linux設(shè)備驅(qū)動并發(fā)控制

2021-01-12 10:22:45

JavaScript并發(fā)控制前端

2021-07-19 09:25:19

數(shù)據(jù)庫MySQL技術(shù)

2010-06-08 12:54:16

UML技術(shù)

2009-02-03 10:19:45

2010-06-13 13:13:12

UML建模

2009-04-01 14:33:33

2017-08-21 10:56:55

MySQL并發(fā)控制

2011-12-30 16:30:39

Java

2011-05-18 16:02:08

XML

2021-07-28 08:32:58

Go并發(fā)Select

2009-07-29 17:44:02

ibmdwJava

2011-12-29 15:35:39

Web

2010-11-08 10:57:05

SQL Server的

2021-08-28 10:06:29

VueJavascript應(yīng)用

2009-06-30 15:32:00

入侵檢測Java Web

2011-11-21 18:19:20

Web iMC

2025-02-27 08:15:28

點贊
收藏

51CTO技術(shù)棧公眾號