淺談ADO.NET文章系列之二 — 並發更新衝突的處理

來源:互聯網
上載者:User
ado 聲明:這裡只對並發衝突做簡單的分析,所以在前面冠以“淺談”二字,希望大家可以從中看到一般的處理方法和注意的事項,如果有什麼疏漏,那也相當地自然,畢竟本人水平有限,還有很多需要提高的地方,希望各位朋友不吝指正!

一.為什麼會產生並發在我們使用ado.net對資料庫中資料進行操作時,很有可能這種操作或類似地操作也在網路內其他使用者中進行著,那麼就難以避免地會遇到更新操作失敗的情況。因為為了更好地提高效能,ado.net採用了中斷連線的方式。也就是說要先把資料的副本讀取到用戶端,那麼也容易引起多個使用者同時更新一條記錄產生資料並發異常。這個操作,很可能是其他使用者刪除了該行記錄,也可能是修改了某個欄位。這個問題是個進階話題,也一直是資料操作中的痛點。在下面我只做簡單地討論和分析。二.解決方案通常處理並發衝突的方法有兩個。一個是保守式並發處理,一個是開放式並發處理。所謂的保守式並發處理,就是使用鎖使某條記錄被讀出後就一直被鎖定,直到該使用者提交更新。它的壞處正如它的名字一樣,相當地保守。因為如果該使用者讀完該條資料後就因為有事情而離開或者忘記了來點“更新”操作,那麼其他使用者要一直等待,直到他回來或者被提醒或者自己想起來。很明顯,這不是我們想要看到的(當然,在特定的要求和條件下該方法也有它的優點,否則它也沒有存在的必要了)。相反,開放式並發是我們所要討論的重點,這個也是ado.net推薦使用的方法。什麼是開放式並發處理方法呢?我自己的理解就是要面對並發異常的出現,制定處理方法來解決或者提示使用者這種異常的出現。既然並發不可避免,那麼我們就要作好處理並發衝突的解決方案。這就象一個樂觀的人一樣,他有了疾病,他的心態依然是樂觀向上的一樣,他要把重點放在如何治療上而不是徹底地避免(這個比喻可能不太恰當,見笑了!呵呵)。在寫程式前要考慮到並發出現的可能,根據自己的需要來選擇更新邏輯和方式。三.淺論開放式並發處理的要注意的地方。(這裡也是最容易引起問題的地方,大家要多提意見啊!)

 1.  更新方式的選擇  一般來說,更新方式有緩衝更新和立即更新兩種。緩衝更新,就是使用dataadapter.updte()方法來進行資料的更新。我們可能在datagrid中修改了很多記錄,而只進行一次提交,那麼這種操作如果從讀取資料開始(或上次更新操作)算起所距離的時間越長,也就越容易引起並發衝突。相對來說,立即更新,也就是使用command.executenoquery()方法,直接來提交對一條記錄的修改應該比較快捷,但仍然不能完全避免衝突的出現,但仍然是我推薦的方式。2.  更新邏輯的選擇  更新邏輯:我理解的就是按照哪種更新的方式來對資料進行更新操作。它可以是包含所有列的;可以是只包含主鍵列的;可以是包含主鍵列和被更新列的;可以是包含主鍵列和時間戳記列的。我們來看這4中更新邏輯的差異。如果你以前用過Pb來進行編程,那麼可能你理解起來就相對容易。因為pb裡面的三種更新邏輯和這裡的有很多相似的地方。為了更好的說明問題,我們來舉一個例子。有表 table1( id,name,sex,address,salary,tamp) 其中的tamp是時間戳記列。那麼對應的更新邏輯為:(1)                 update table1 set id=?,name=?,sex=?,address=?,salary=? Where id=? And name=? and address=? And salary=? (2)                 update table1 set id=?,name=?,sex=?,address=?,salary=? Where id=?(3)                 update table1 set id=?,name=?,sex=?,address=?,salary=? Where id=? And name=? (這裡假設只對name列進行修改,而其他列不變)(4)                 update table1 set id=?,name=?,sex=?,address=?,salary=? Where id=? And tamp=?     我們來對這4中邏輯進行簡要的說明:第1種也是預設地一種,把所有的欄位都包含進去,那麼當有使用者A ,B讀取了資料後,A成功更改了一行記錄中的name,那麼如果B再要更改同行記錄時,由於WHERE條件中要求滿足所有的欄位,而這個時候NAME已經改變了,這樣他將更新失敗。對於第2種方法,它只包含主鍵,那麼也就是說如果不修改主鍵(或刪除)(修改主鍵是危險的,應該避免!)的話,都會成功,但A更新成功了,B也更新成功了,但B的更新覆蓋了A的更新,這個時候B甚至不知道原來自己更新的時候記錄已經有了變化,A也不知道自己的記錄已經被覆蓋。這種方法也叫做“後來居上”的方式。也就是後面的覆蓋前面的操作。這裡也說一句,我一般採用該種方法,但不是說它有多好,而是為了快速開發。第3種方法,既包含主鍵也包含更新的欄位。假設A成地更新了一條記錄的NAME欄位,B更新該行記錄的SEX欄位,那麼B也會成功的實現自己的更新。但同樣,如果沒有重新整理顯示的話,他們都不知道該行記錄的對應欄位發生了變化。在PB裡,這種方式是被提倡使用的。但在.NET裡這種方式的構建相對來說比較麻煩,寫的代碼也比較多,是種比較消耗時間和精力的。對於最後一種方式,它採用了時間戳記列作為更新條件,時間戳記能反映記錄更新的變化。如果時間戳記變化了,那麼該記錄自然已經被別人更新過了。這種方法是這裡推薦的方法。當然每種更新邏輯都有自己的好處,我們也不能特意地使用哪種,要根據自己的系統的情況來選擇。一般來說,第1種方式是dataadapter預設產生的,而第2種,第3種,第4種都要我們自己來設定。手動地建立更新邏輯(就是指定對應的insertcommand的commandtext和updatecommand的commandtext和deletecommand的commandtext)是個費時費力的過程,但更新效率也相對較高。

 

 3.  更新邏輯產生的說明  如果更新邏輯是使用dataadapter的嚮導來產生的,那麼可以在進階選項裡把“使用開放式並發”的複選框去掉。這樣將實現使用這種更新策略。對於那些只是設定dataadapter的selectcommand.commandtext而使用commandbuilder的建構函式來產生(或使用相關的getupdatecommand等方法)更新邏輯的程式,這裡建議不要這麼做,雖然這樣比較方便,但也為更新時的效率和可控制性打了折扣。希望大家注意,不到萬不得以,不要使用。4.  如果更新方式和更新邏輯都選擇好了以後,那麼就要考慮使用事務了。在事務中進行更新操作的結果就是要麼全部成功,要麼都不成功。簡單地說就是“要麼全做,要麼不做(呵呵,記得剛畢業在濟南工作的時候,項目組長問我,我就是這麼回答的!)所以使用事務的程式碼是比較安全的。類似如下的代碼:

Dim mytransaction As oledbTransaction

            Try

                conn.Open()

                mytransaction = conn.BeginTransaction

                cmd1.Transaction = mytransaction ‘這裡假設已經建立了cmd1對象

                cmd1.ExecuteNonQuery()  

                mytransaction.Commit() '提交事務

 

         Catch ex As Exception

                mytransaction.Rollback() '復原事務

                Return -1 ‘做一些其他處理

         Finally

                conn.Close()

   End Try

 

  說明:對於dataadapter.update方法,如何使用事務呢?其實dataadapter本身並不進行資料更新,而是它的insertcommand,updatecommand,deletecommand。那麼就象上面一樣設定這三個command對象的Transaction屬性就可以了。其他的和上面沒有什麼不同。

 5.  既然我們在前面說了採用開放式並發處理,就要對異常進行相應的捕獲,給出相應的提示資訊和處理辦法。對於那些可能引起異常的代碼都要包含在try     …  end try 塊之間,這是一個很好的習慣。一般可以採用類似下面的操作:

Try

            Sqldpr1.Update(ds1.Tables("table1"))

 Catch Ex As Data.DBConcurrencyException '並發衝突的異常

     ‘做相應的處理  End try 說明:這裡的做相應的處理,可以是把最新的行從資料庫中讀出來更新現有的行(當然如果該行被刪除例外),也可以重新填充資料(fill操作)。這個時候我們可以作出判斷,該行是被刪除的情況,可以使用一個函數將Ex.row(“ID”)作為參數傳遞過去,使用一個command.executeschar方法來判斷是否記錄存在,使用executereader或fill來取得已經變化的記錄或重新整理全部記錄。這裡提到了update()方法引發的異常,如果是立即更新引起的,處理的方式也是一樣的。

 總結:  由於時間和本人水平的問題,這個問題不能討論的太深入,請大家原諒。可能裡面涉及的範例代碼比較少(呵呵,真的很少),讀起來可能有些頭疼,但我想如果你對資料更新的原理如果比較熟悉應該可以理解其中的意思。最後,還是希望大家能多提意見!有時間一定給出相關的範例代碼。                                



相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。