web後臺多用戶操做同一條數據同步問題

場景(問題)描述以下:程序員

0,用戶A、B同時打開一個頁面,頁面顯示,客戶表T_CUSTOMER字段(C_NAME、C_AGE)數據庫

姓名:張三,年齡:25安全

1,A 將姓名「張三」改成「張三1」,而後保存服務器

2,B 將年齡「25」改成「30」,而後保存網絡

這樣A的操做就被覆蓋了,姓名又變回「張三」了,你們通常怎麼到處這種狀況?併發

這裏給出一個較易用的解決方案oracle

給表添加一字段:LAST_UPDATE,即最後更新時間性能

回放場景設計

0,用戶A、B同時打開一頁面,面頁顯示:版本控制

姓名:張三,年齡:25,LAST_UPDATE:2008-10-17 13:45:00

1,A 將姓名「張三」改成「張三1」,而後保存

重點在這裏:更新數據時WHERE條件裏多一條件:AND LAST_UPDATE = '2008-10-17 13:45:00'

更新成功,此時觸發器會將當前時間「2008-10-17 13:46:00」賦值給LAST_UPDATE

2,B 將將年齡「25」改成「30」,而後保存

B更新數據時WHERE條件裏也有這個條件:AND LAST_UPDATE = '2008-10-17 13:45:00',但此時LAST_UPDATE的值已經在A修改記錄時變成2008-10-17 13:46:00

下面要作的就是給出提示了:喔喲,此信息在你發呆這段時間已被人改過啦,因此你須要返工。

觸發器代碼以下:
===================================================
CREATE OR REPLACE TRIGGER T_CUSTOMER
BEFORE UPDATE ON T_CUSTOMER
FOR EACH ROW
/*
記錄最後修改時間
*/
BEGIN
:NEW.LAST_UPDATE := SYSDATE;
END;
===================================================

若是觸發器不熟悉或者只是不喜歡用觸發器,徹底能夠修改記錄時同時給LAST_UPDATE字段賦值,以此替代觸發器的做用。

 

 

 

【併發操做】多用戶併發操做的解決方案

【問題】在之前的系統開發中,常常遇到一個一樣問題,就是多個用戶同時併發操做一條記錄,此次在交易系統開發過程當中,又出現了這樣問題。好比交易商A提交單子,由審覈人員B審覈,此時A正在修改單位,B也正在查看這條記錄,A先修改保存後B再審覈保存,致使B審覈經過的記錄不是他所看到的。

【分析】仔細考慮問題,大概分析了三個方法, 並肯定了一個可行的方案,可能還有不完善的地方,但解決現有問題仍是綽綽有餘的。

最早想的是在交易業務代碼中用lock對修改方法加鎖,運行時注入單例,而且對方法加同步鎖,保證了業務數據的正確性, 可是效率低下,用戶在使用中不方便,背離了系統能夠併發操做的原則。

而後考慮使用悲觀鎖,此次運行時注入原型,併發操做效率提升, 可是,在同步處理數據庫表時又形成鎖表,這樣併發效率依舊很低。

最後考慮樂觀鎖, 只是一種數據版本校驗機制,它不作數據庫層次上的鎖定,須要在要併發操做的主表中加入一個"VERSION"字段或者「LASTUPDATETIME」,若是研究過oracle的SCN應該有殊途同歸之妙,它的原理是這樣:運行時注入原型,這時數據表並不鎖住,只是每次update或insert時將VERSION更新, 當下次update,insert時,會校驗VERSION,若是不一致,此時提示信息已經修改過了,而且在事務控制下rollback,這樣,保證了數據的正確性,而且也不影響併發操做的效率。可是出現的問題是:若是A讀了數據,將來及更新,B先更新了數據, 那麼他將提交不上數據,由於VERSION已經失效,這樣就形成了A從新讀取數據,從新填寫單據信息。 這也是樂觀鎖一個缺點,能夠在更新前臨時保存A填寫的數據,再在跳轉頁中加載這些數據,保證了交易商不用麻煩再次輸入這些數據,更新成功則清空這些臨時數據

【結果】

樂觀鎖在併發操做問題上,保證了業務效率和數據的正確性,基本能夠採用這種方案解決交易中併發問題。

●悲觀鎖:指在應用程序中顯式地爲數據資源加鎖。悲觀鎖假定當前事務操

 

縱數據資源時,確定還會有其餘事務同時訪問該數據資源,爲了不當前

 

事務的操做受到干擾,先鎖定資源。儘管悲觀鎖可以防止丟失更新和不可

 

重複讀這類併發問題,可是它會影響併發性能,所以應該很謹慎地使用悲

 

觀鎖。

 

●樂觀鎖:樂觀鎖假定當前事務操縱數據資源時,不會有其餘事務同時訪問

 

該數據資源,所以徹底依靠數據庫的隔離級別來自動管理鎖的工做。應用

 

程序採用版本控制手段來避免可能出現的併發問題。

 

----------------------------------------------------------------------------

http://blog.163.com/lqc-rabbit/blog/static/7594799320081131113720281/

.Net中的事務處理(多用戶同時操做一條信息時是用-併發) [Web Applicaion in C#]
SqlConnection myConnection = new SqlConnection("Data Source=localhost;Initial Catalog=Northwind;Integrated Security=SSPI;");
myConnection.Open();

SqlTransaction myTrans = myConnection.BeginTransaction(); //使用New新生成一個事務
SqlCommand myCommand = new SqlCommand();
myCommand.Transaction = myTrans;

try
{
myCommand.CommandText = "Update Address set location='23 rain street' where userid='0001'";
myCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine("Record is udated.");
}
catch(Exception e)
{
myTrans.Rollback();
Console.WriteLine(e.ToString());
Console.WriteLine("Sorry, Record can not be updated.");
}
finally
{
myConnection.Close();


須要注意的是,若是使用OleDb類而不是Sqlclient類來定義SQL命令和鏈接,咱們就必須使用OleTransation來定義事務。


數據庫系統程序員須要比通常應用軟件程序員懂得更多。通常程序員對事務處理的理解不夠全面。事務處理的關鍵是在提交事務或者取消事務時,萬一系統崩潰了,數據庫在再次啓動時,仍然須要保持數據可邏輯一致性。

最簡單的事務處理過程以下:

1. 開始一個事務。進入「事務待命」狀態。
2. 在「事務待命」狀態,記錄事務中改變的數據庫記錄。此改變不能直接改變數據庫中的值,必須先用一個順序的「事務日誌」記錄在一邊。同時,對於要改變的原始記錄加鎖,讓其它用戶沒法讀和寫。(考慮銀行取款問題,能夠發現若是此時兩個用戶都在對同一賬號取數,而後減去必定金額,在前後寫回數據庫,銀行就虧錢了)。若是記錄已經被其它事務加鎖,則報錯;同一事務中卻能夠重複加鎖。
3. 在「事務待命」,若是用戶給出commit transaction命令,則進入「事務拷貝」狀態,拷貝全部加鎖的記錄成備份。
4. 上面3執行完,則進入「事務更新」狀態,用「事務日誌」中記錄一一更新實際的數據庫記錄。
5. 上面4執行完,則進入「事務結束」狀態,釋放全部的記錄鎖,而後拋棄「事務日誌」和備份的原數據庫記錄。
6. 上面5作完後,事務被刪除。

可是,最爲關鍵的是,事務系統必須執行如下過程:一但數據庫因爲軟件、硬件問題發生故障,重啓動後,一旦有事務沒正常刪除,則:

7. 若是在「事務待命」、「事務結束」狀態,則從新從5中結束事務的動做開始執行。
8. 若是在「事務更新」狀態,則從新從4開始更新記錄,並繼續想下執行。結果,雖然系統崩潰過,但事務仍然能正常提交。

Informix、Oracle、DB2等數據庫的實際事務處理流程更復雜,目的是具備更好的抵抗系統錯誤性質,由於事務保護是業務系統安全穩定的最後一道防線(比用2個CPU、熱備份等更重要。由於那些方法對已經混亂錯誤的數據照樣保護,結果常常形成更多問題)。因爲事務處理的流程比通常程序想像得複雜,所以可能會感到用起來比較繁瑣。可是瞭解事務在保護數據庫方面的良苦用心,就能夠更好地設計出更靈活的業務流程。

若是「一個完整的事務可能包括a,b,c,d四個小事務」就比較奇怪。既然是個過程構成一個事務,不必中間在劃分爲4個小事務,問爲中間任何操做出錯都須要整個「回滾」到a以前。在執行完a後用一個if語句判斷要不要再執行「b,c,d」就行,end if以後提交事務。

應用中包含的事務應當儘可能讓它「瞬間」完成,避免在比較忙時形成用戶進程的互鎖。事務比較頻繁的系統,一秒鐘有幾個用戶互鎖就可能形成嚴重問題,由於事務是以一個穩定的頻率來的,而服務器上互鎖的進程越積越多,幾個小時後,可能有上百臺機器都死掉了,只能一臺一臺地從新開機,花費不少時間、金錢,還會被用戶罵死!

可是並非說事務之間就不能有用戶交互。能夠在用戶3分鐘還沒確認後,就自動報告錯誤,而且取消事務。不過我從不冒這個險,而是使用下面方法。

將事務拆分紅兩段,須要很是深刻地研究用戶業務流程,研究用戶在發現業務數據不一致時是如何糾正的,而且繼承用戶手工操做流程。這樣,軟件分析的工做量相應加大了。有時,這是必然的,應當說服用戶接受這種現象,而且與開發者一塊兒逐步解決。

好比,賣彩票的交易,用戶輸入彩票號碼,此時在POS機打印彩票而且記帳。這並不須要在賣彩票時與後臺服務器實時聯網,只要每隔10分鐘上傳一次數據就好了。只有這樣,才能在現有的硬件和網絡條件下使得彩票銷售開展起來。若是開發者固守者彩票號碼錄入、服務器記帳、前臺打印合併爲一個事務的天真想法,其產品必定會在激烈的市場中敗陣。

固然,隨着硬件、軟件、網絡的不斷變化,如何靈活應用事務的方法會不斷變化,沒有必定的規矩,關鍵要看軟件的效果。雖然大的事務可能不斷拆分紅小的事務,中間用業務流程聯繫起來;同時,合併一些小的事務或者由計算機自動處理業務數據不一致問題,從而給用戶提供網絡上的「傻瓜相機」同樣的易用、穩定的產品仍然是今天最有挑戰意義的軟件工程目標。 --------------------------------------------------------------------------------------

這個問題不是C#處理的,而是你調用的存儲過程或批查詢須要處理的,若是你用C#執行一系列的更新語句的話,你可使用ADO .NET SqlClient的事務來控制併發時的數據完整性!

SqlConnection conn=new SqlConnection(connectionstr);

SqlTransaction mytran=conn.BeginTransaction();

SqlCommand cmd=new SqlCommand();

cmd.Connection=conn;

cmd.Transaction=mytran;

cmd.CommandText=.....;

int rc=cmd.ExecuteNoQuery();

 

mytran.Commit();

....

你能夠經過錯誤處理機制來控制事務提交仍是會滾...

 

-------------------------------------------------------------------------------------------- 我在程序中使用一種原始的方法處理須要鎖定的內容。好比個人表中存儲有訂單的行項目,每次只容許一個用戶對行項目進行編輯。創建「鎖定表」,每當用戶編輯訂單時,在"鎖定表"中加入訂單號。當加入失敗時則說明已有用戶在編輯訂單,當用戶退出訂單或鎖定時間超過一個閾值時則刪除鎖定記錄,容許其餘用戶編輯並鎖定訂單。這樣處理適合鎖定多行的訂單類數據,鎖定表中能夠保存其餘附加信息。還有一種方法在數據庫中使用事務。使用事務更新數據庫,這樣能夠保證同一時間只有一個用戶能夠對行更新。

相關文章
相關標籤/搜索