5

我想知道是否有任何方法可以使用 MySQL Cluster 之类的分布式服务器对部署在多台服务器上的 asp.net Web 应用程序执行“锁定”。

例如,以更新帐户余额的经典示例为例。任何两个请求都不应同时更新同一个帐户余额。例如:

会员 1 账户余额为 100。

  • 请求 A 访问服务器 1 为成员 1 的余额增加 100
  • 请求 B 访问服务器 2 为成员 1 的余额增加 50

因此请求 A 将余额从 100 更新为 200 并保存。
请求 B 将余额更新为 150,并保存。

这些都发生在同一时间,因此丢失了信息,因为最终结果应该是 250。

如何锁定请求 B 必须等到请求 A 完成,直到它检索到余额。如果它是单个进程,这可以通过应用程序范围的锁来实现。但是,由于有多个独立的进程,这对于服务器 1 来说是行不通的,它没有被锁定,服务器 2 也没有

任何想法或最佳实践如何做到这一点?

4

3 回答 3

4

这就是交易的用途。

将需要原子的操作包装在 aTransactionScope中以将它们注册到显式事务中。

这并不能完全解决陈旧数据的问题,因为一旦事务完成,如果其他并发用户正在使用值进行更新,您仍然会遇到问题。

解决方案是使用表上的一个字段,该字段会随着行的变化而变化——在 SQL Server 2008 中,这是rowversion类型。

仅在未更改时才更新该行rowversion- 如果已更改,则通知用户并带回当前值而不进行更新。

于 2011-12-21T14:08:23.840 回答
1

在我创建的 ORM 中,我实现了一个锁定机制。每种类型的实体,例如产品、客户等,都有 2 个附加字段:“LockedBy (int)”和“LockedAt (datetime)”。

LockedBy 包含锁定实体的用户 ID,lockedAt 包含锁定实体的时间戳。

因此,当用户想要开始编辑实体时,代码会经历这个过程:

从数据库中获取实体,'1' 是 ProductID

Product p = new Product(1);

将实体锁定到当前登录的用户

entity.Lock();

将实体保存/提交到数据库,如果登录用户有权保存实体,则 Save() 调用 LockCheck() 返回 true。

entity.Save();

在以下情况下,用户有权保存实体:

 (LockedBy < 0 || LockedBy == LoggedInUser.UserID || LockedAt < DateTime.Now.AddMinutes(-30))

注意:用户可以编辑超过 30 分钟前被锁定的实体。如果另一个用户打开了实体(在编辑屏幕中),那么它会每 15 分钟弹出一次并询问用户是否还在,如果是,它会发出一个请求,将 LockedAt 增加到现在(如滚动锁)

此时没有其他用户可以编辑此实体!

代码/用户可以随心所欲地自由编辑该实体,并确保它背后没有改变:)

一旦用户停止编辑代码调用:

entity.Unlock()

然后

entity.Save()

这然后释放实体供其他用户编辑它

于 2012-06-27T16:45:32.877 回答
1

这就是像Redis 的 pub/sub 机制这样的系统可以帮助您的地方。它本质上是一种向订阅者(其他负载平衡的服务器)发送消息以让他们知道事件发生的方法。ServiceStack Redis 客户端完全支持这一点。

于 2013-03-07T15:54:11.290 回答