2009-07-19 43 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”。

马克

相关问题