2009-07-19 44 views
3

我有一個像client/server/db這樣的架構的應用程序。客戶端和服務器之間的通信是WCF(已從asmx遷移)和數據庫是SQL Server 2005.WCF和SQL Server - 如何處理數據更改?

該項目有一個要求,即您無法更新訂單,該訂單已被其他用戶更改(更新)初次閱讀。我認爲大多數應用程序都有一個共同的要求

訂單的更新通常爲:

  1. 客戶端讀取順序 - 一個最初讀副本服務器
  2. 客戶端更新命令存儲(會話) - 返回updated-訂單到服務器
  3. 服務器將從數據庫中再次讀取訂單,並與初始讀取進行比較以檢查訂單是否已被其他用戶更改 - 如果客戶端將被通知重新讀取orde [R
  4. 服務器將保存更改

這種方式來處理數據的變化具有這樣的效果,即在certaint點(3),服務器將有3個(不同的)在內存中的順序的份!任何人都知道另一個策略呢?

我們正在與AspNetBackwardCompability運行WCF,因爲我們需要的會話變​​量來「保持」 最初讀副本 - 它會讓我的一天,如果我們能夠轉儲

回答

2

一個解決方案是在保存時讓客戶端提供最初讀取的值和更新的值。然後,您不需要會話中的原始值的副本。

數據集必須存儲兩個版本(DataRowVersion.Original和DataRowVersion.Current)的內置功能,但你必須提供自己的方法來做到這一點(例如OperationContract的:

SaveMyData(MyType original, MyType updated); 

然後,您可以保存到數據庫中這樣:

UPDATE MyTable 
SET Col1 = @NewCol1, Col2 = @NewCol2, ... 
WHERE Col1 = @OldCol1, Col2 = @OldCol2, ... 
IF @@ROWCOUNT = 0 ... update failed ... 

或者你可以在你的表中的TIMESTAMP/ROWVERSION列您往返給客戶,並對其進行測試更新時間:

UPDATE MyTable 
SET Col1 = @NewCol1, Col2 = @NewCol2, ... 
WHERE PKCol = @PK AND TimeStampCol = @OldTimeStamp 
IF @@ROWCOUNT = 0 ... update failed ... 

您當然要依靠客戶端在保存時正確返回原始值/原始時間戳。但這不是一個安全問題 - 惡意客戶無法比基於會話的解決方案造成更多的損失。

+0

你好,Joe 我覺得這是一個很好的方法,但發送兩個版本(原件和電流)再次給出了必須向前和向後發送到服務器產生額外的數據 - 我們正在與掙扎相當數據量。我更喜歡你的時間戳版本。 – Rotte2 2009-07-21 19:39:08

1

什麼是防止併發改變發生在3,4之前?

處理這個問題的通常方法是消除第3步(除非在可重複讀取隔離級別中完成,並且這完全是過度殺毒),並且應用樂觀跳變的改變(即樂觀併發性模型)。爲了強制確保沒有任何更改,可以使用包含全部舊值的WHERE子句,或者添加到WHERE子句特殊列,該列在處更新,每更新,如時間戳或行版本。

如果更新是無操作的(它沒有找到舊值,使用各種方法檢查,例如檢查@@ ROWCOUNT或使用OUTPUT子句),則可以讀取新的,已修改的值並僅在例外情況下通知客戶端。

1

一個有狀態的服務,例如你已經實現的是一個很大的服務反模式。作爲一般原則,Web服務應該是無狀態的,否則您的可伸縮性可能會受到影響。對於樂觀鎖定,請爲表使用時間戳列。將其作爲併發令牌返回給客戶端,並將其返回並更新之前與數據庫中的值進行比較。我在sql服務器上生,但oracle已經選擇了可以幫助你的更新語句。

如果數據分佈在多個表中,請考慮使用存儲過程的合適鎖定策略。

0

我喜歡Joe的方法 - 這也是我所推薦的。

在您的初始讀取中,將實際DataContract中的TIMESTAMP列的值從主表中發回客戶端,或作爲WCF響應消息中的標頭髮回。

如果要更新數據,請將客戶端的初始時間戳值發送回服務器。然後服務器將首先檢查該時間戳值是否已更改,如果是,則拋出FaultException並且不更新數據。只有當時間戳值仍然與客戶端在UPDATE調用中返回的值相同時,服務器是否會實際執行更新。

我會推薦使用SQL Server TIMESTAMP數據時間(這實際上不是什麼與日期和/或時間有關的任何事情 - 實際上它只是一個獨特的,不斷增加的數字),因爲這樣做更準確而不是DATETIME,並且每當您寫入表中的行時,它都會由SQL Server自動更新。成爲檢查更新的完美「標記」。

通過這種方法,您需要傳遞的所有內容都是一個8字節的時間戳值 - 無需具有整個數據行的三個精確副本。

看到這篇文章「Understanding TIMESTAMP (ROWVERSION) in SQL Server」。

馬克