Sql server WCF和SQL Server-如何处理数据更改?

Sql server WCF和SQL Server-如何处理数据更改?,sql-server,wcf,Sql Server,Wcf,我有一个类似client/server/db的应用程序。客户端和服务器之间的通信是WCF已从asmx迁移而来,数据库是SQLServer2005 该项目有一个要求,即您不能更新订单,该订单在您首次读取后已被其他用户更改或更新。我认为这是大多数应用程序中的一个常见要求 订单的更新通常如下所示: 客户端读取订单-最初读取的副本存储在服务器上的会话中 客户端更新订单-将更新后的订单返回给服务器 若订单已被另一个用户更改,服务器将再次从数据库中读取订单,并与初始读取进行比较以进行检查,以防客户端收到重新

我有一个类似client/server/db的应用程序。客户端和服务器之间的通信是WCF已从asmx迁移而来,数据库是SQLServer2005

该项目有一个要求,即您不能更新订单,该订单在您首次读取后已被其他用户更改或更新。我认为这是大多数应用程序中的一个常见要求

订单的更新通常如下所示:

客户端读取订单-最初读取的副本存储在服务器上的会话中 客户端更新订单-将更新后的订单返回给服务器 若订单已被另一个用户更改,服务器将再次从数据库中读取订单,并与初始读取进行比较以进行检查,以防客户端收到重新读取订单的通知 服务器将保存更改 这种处理数据更改的方法的效果是,在确定的第3点,服务器将在内存中拥有订单的3个不同副本!有人知道这方面的另一个策略吗


我们使用AspNetBackwardCompability运行WCF,因为我们需要Session变量来保存最初读取的副本-如果我们可以转储它,它将成为我的一天

有什么可以防止在3之后、4之前发生并发更改

处理这一问题的通常方法是消除步骤3,除非在可重复读取隔离级别中执行,否则步骤3是不正确的,这完全是过激的,并且乐观地应用更改,即乐观并发模型。为了确保没有任何更改,您可以使用包含所有旧值的WHERE子句,或者向WHERE子句中添加在每次更新时更改的特殊列,如时间戳或行版本


如果更新是不可操作的,那么它将被删除。它没有找到旧值,这是通过各种方式检查的,如检查@@ROWCOUNT或使用OUTPUT子句,然后您可以读取新的、修改的值并通知客户端,只有在异常情况下。

您实现的有状态服务是一个大服务反模式。作为一般原则,Web服务应该是无状态的,否则您的可伸缩性可能会受到影响。对于乐观锁定,请为表使用时间戳列。将其作为并发令牌返回给客户端,客户端将原封不动地返回,并在更新之前与DB中的值进行比较。我是sql server上的原始用户,但oracle有select for update语句可以帮助您


如果数据分布在多个表中,考虑使用存储过程的一个合适的锁定策略。

< P>一个解决方案是让客户端在保存时同时提供初始读取值和更新值。这样,在会话中就不需要原始值的副本

数据集具有存储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 ...

当然,在保存时,您需要依靠客户端正确返回原始值/原始时间戳。但这不是一个安全问题-恶意客户端不会比基于会话的解决方案造成更大的破坏。

我喜欢Joe的方法-这也是我的建议

在初始读取中,将时间戳列的值从主表发送回客户机,可以是在实际的DataContract中,也可以是作为WCF响应消息的头

当您想要更新数据时,将初始时间戳值从客户端发送回服务器。然后,服务器将首先检查时间戳值是否已更改,如果已更改,则抛出FaultException而不更新数据。只有当时间戳值仍然与客户端在更新调用中返回的值相同时,服务器才会实际执行更新

我建议使用SQL Server时间戳数据时间,顺便说一句,它实际上与日期和/或时间没有任何关系——它只是一个唯一的、不断增加的数字,因为它比日期时间准确得多,并且每次写入表中的行时,SQL Server都会自动更新它。成为检查更新的完美标记

使用这种方法,您只需要传递一个8字节的时间戳值——不需要有整个数据行的三个精确副本

看看这篇伟大的文章


Marc

嗨,Joe,我认为这是一个很好的方法,但同时发送原始版本和当前版本会产生额外的数据,这些数据必须再次发送到服务器,而且我们正在为大量数据而挣扎。我更喜欢你的时间戳版本。