1. 程式人生 > >web後臺多用戶操作同一條數據同步問題

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

無法 tro 語句 if語句 動作 金錢 pen tex 業務

場景(問題)描述如下:

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

姓名:張三,年齡:25

1,A 將姓名“張三”改為“張三1”,然後保存

2,B 將年齡“25”改為“30”,然後保存

這樣A的操作就被覆蓋了,姓名又變回“張三”了,大家一般怎麽處處這種情況?

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

給表添加一字段: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();

....

你可以通過錯誤處理機制來控制事務提交還是會滾...

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

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