4

我想知道是否有任何方法可以在部署在多个服务器上的asp.net web应用程序上执行'锁定',使用像MySQL Cluster这样的分布式服务器。锁定服务器场(asp.net)

例如,以更新帐户余额的经典示例为例。没有两个请求应该同时更新相同的帐户余额。例如:

成员1个的帐户余额是100

  • 请求A访问服务器1至100加至构件的天平1
  • 请求B访问服务器2至50添加到成员的平衡1

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

这些都在同一时间发生的准确,从而失去了信息,最终的结果应该是250

一个人怎么可以锁定,从而请求B将不得不等待,直到请求A完成,直到它检索余额。如果它是一个单独的进程,这可以通过应用程序范围的锁来实现。但是,由于存在多个独立进程,因此对于服务器1来说这不起作用,因此它不会被锁定,也不能对服务器2执行任何想法或最佳实践。

+0

这是现代基于云的应用程序中的典型问题。它真的取决于数据库。如果您的数据库支持交易,请使用它们!如果你想得到一般的想法,你应该检查出'两阶段提交协议'作为开始:http://en.wikipedia.org/wiki/Two-phase_commit_protocol – Nappy 2011-12-21 14:50:45

回答

4

这就是交易的目的。

TransactionScope中包含需要原子化的操作,将它们注册到明确的事务中。

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

解决方案是使用表中每当行更改时都会更改的字段 - 在SQL Server 2008中,这是rowversion类型。

如果rowversion未更改,则只更新该行 - 如果已更改,则通知用户并在不进行更新的情况下恢复当前值。

+0

我使用NHibernate作为一个ORM解决方案。无论如何,你可以进行检查,以便如果对象的'版本'发生了变化,它会抛出一个错误,然后应用程序可以捕获该错误,并基本上重新启动该进程,直到该版本尚未更改? – 2011-12-21 15:51:51

+0

@KarlCassar - 我不知道nHibernate足以告诉你。 – Oded 2011-12-21 15:55:51

+0

如果您定义版本列/属性,则nhibernate将引发异常“行由另一事务更新”。 – iceburg 2016-03-29 04:05:06

1

在我创建的ORM中,我实现了一个锁定机制。每种类型的实体(如Product,Customer等)都有两个附加字段:'LockedBy(int)'和'LockedAt(datetime)'。

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

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

获取从DB实体,“1”是产品ID

Product p = new Product(1); 

锁定实体当前登录的用户

entity.Lock(); 

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

entity.Save(); 

用户有权保存实体,如果:

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

注:用户可以编辑这些被锁定在30分钟前的实体。如果另一个用户打开了该实体(在编辑屏幕中),那么每隔15分钟它会弹出并询问用户是否仍然在那里,如果是,它会执行一个请求,将LockedAt增加到Now(如滚动锁)

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

代码/用户可以自由地尽可能多地希望一旦用户停止编辑代码编辑这个实体可以肯定,它并没有改变它背后回来:)

电话:

entity.Unlock() 

然后

entity.Save() 

这则解放了实体供其他用户编辑

+0

然后我注意到这是超过6个月大:/ – Metalstorm 2012-06-27 16:46:37

1

这是像Redis' pub/sub mechanism这样的系统可以帮助您的地方。它本质上是一种向订阅者(其他负载均衡的服务器)发送消息以让他们知道事件已经发生的方式。 ServiceStack Redis client已完全支持这一点。