许多具有桌面应用程序背景的人会想知道这是如何在 Web 应用程序中完成的。
锁定记录标志
桌面世界中的一种方法是在行上有一个布尔列,指示它正在被编辑以及由谁编辑。您当然可以使用网络应用程序执行此操作,但这是一种非常糟糕的方法,因为如果用户访问编辑页面,将记录置于锁定状态,然后离开该页面,它将永远处于锁定状态。您没有明确的方法来判断用户尚未打开编辑页面。
时敏锁
航空公司预订方法是上述方法的变体,但您还会有一个 LockedUntilUtc,它是一个日期时间,指示记录锁定多长时间。假设 Bob 访问一个页面以获取记录,当通过 GET 操作提供 apge 时,您还设置了锁定标志,并将 LockedUntilUtc 设置为未来 10 分钟。 5 分钟后,Sarah 访问该页面,但收到“当前锁定”错误,因为您检查了 LockedUntilUtc 并且它当前处于未来状态。又过了 6 分钟(自锁定以来总共 11 分钟),有人访问该页面,LockedUntil 已过去,因此您将锁定授予新用户。
这似乎是一个合理的妥协,但它充满了肯定会让用户感到沮丧的问题。首先,没有简单的方法可以对需要访问权限以编辑记录的用户进行排队。 Sarah 可以尝试 10 次,然后就过了 10 分钟,Jimmy 访问了该页面,因为他是锁过期后第一个访问的人,所以他在 Sarah 没有机会的情况下抢到了下一个锁。 Sarah 致电您的服务台,并表示她等了 10 分钟锁才过期,而现在已经过去 15 分钟了,她仍然无法访问该页面。您的服务台可能怀疑她是否真的等了整整 10 分钟,然后来来回回。
您还必须为当前拥有锁的人实现客户端计时器/显示,以便他们知道在锁过期之前还剩下多少时间。
乐观并发
在大多数情况下这是正确的方法。您实际上根本不以任何方式锁定记录。相反,许多用户可以访问编辑页面。当他们保存编辑时,表单包含原始值和新编辑的值。服务器会将表单中的原始值与数据库中的当前值进行比较,以查看是否存在临时编辑。
The original值来自过去的某个时刻(当 Bob 最初访问编辑页面时)。这current价值观是从现在开始的。从过去到现在,如果 Sarah 也访问过编辑页面,并成功保存了对数据库值的更改,那么 Bob 的original值将不同于current数据库中的值。因此,当 Bob 尝试保存他的更改时,服务器将看到他的更改original值不同于currentDB 中的值,并抛出错误。您需要决定如何处理这种情况。通常,您让用户知道其他人已经编辑了该页面,然后刷新页面,他们就会丢失所做的编辑。实体框架支持乐观并发。
Ajax 化乐观并发
您还可以让客户端偶尔使用原始值 ping 服务器,以便服务器可以检查您的页面是否过时(即其他用户更改了某些内容)并弹出一条消息。这可以通过提前通知用户其他用户已编辑该页面来改善用户体验。因此,他们在进行编辑方面并没有取得多大进展,无论如何他们都会丢失这些编辑。他们还可以在浏览器中记下/复制/粘贴他们的编辑,以便刷新页面并参考他们更改的内容。
SQL Server 中有一个时间戳列,它可以与实体框架协同工作,以降低检查更改所涉及的开销。这样您就不需要在每个客户端中保留原始值的完整记录并将它们来回传递:http://www.remondo.net/entity-framework-concurrency-checking-with-timestamp/ http://www.remondo.net/entity-framework-concurrency-checking-with-timestamp/
细粒度编辑
我们经常使用的一种方法是对每个字段进行 ajax 化,并立即提交对单个字段的编辑。这是使用名为 x-editable 的 jquery 库来完成的。用户编辑单个字段,确认编辑,然后将该值发送到服务器。如果您想检查整个记录或仅检查单个字段的更改,可以将其与乐观并发结合起来。如果检测到更改,则您拒绝编辑并刷新页面。这对于用户来说可能是一种更加友好的体验,主要是因为用户在编辑单个字段时会立即收到“另一个用户编辑的页面”错误。这可以防止他们浪费大量时间编辑大量字段,却发现他们的编辑被拒绝,他们不得不再次重做所有编辑。相反,他们编辑单个字段,收到错误,页面刷新,他们只需重复该字段编辑并从那里继续.
http://vitalets.github.io/x-editable/demo-bs3.html http://vitalets.github.io/x-editable/demo-bs3.html