RavenDB 每秒能处理数十万的请求,这是因为它本质上是并发的。那么这就引出了并发问题,如果有多个请求同一时间同时修改同一个文档,就会出现最后一个被执行的请求将会获胜,它的修改内容将被保留在文档中。在 RavenDB 中 last write wins 模型是默认选项,这个模型出现在对文档的修改和删除的情况下,在创建文档时是不会执行这个模型规则的,因为 RavenDB 它知道请求是要创建一个新文档,并会设置预期的更改向量。
TIP:什么是更改向量? 这个概念在 RavenDB 被深入的使用,它由节点 ID 和 etag 列表组成。节点 ID 是节点的唯一标识,etag 是64位数字,etag 在每次操作的时候都会递增加一。更改向量全局唯一的标记文档的版本,用来进行乐观并发控制,用于内部的操作和缓存。
前面说了那么一堆,现在我们来看看如何解决这个问题。解决方法有三种:
要求 RavenDB 在多个级别开启乐观并发,代码如下:
代码语言:javascript复制store.Conventions.UseOptimisticConcurrency=true;
在特定会话中开启乐观并发,代码如下:
代码语言:javascript复制session.AdvancedUseOptimisticConcurrency=true;
在某个操作总开启乐观并发,代码如下:
代码语言:javascript复制session.Store(entity,changeVector);
上面三种方法都会使 RavenDB 客户端将预期更改向量发送给服务端,服务端收到后会和当前更改向量进行比较,如果不一致就会抛出 ConcurrencyException 异常,并终止事务。这里有个有意思的地方,前两种方法都是使用的加载文档时 RavenDB 服务端提供的更改向量,第三种方法则允许我们可以执行离线乐观并发检查,也就是说我们的应用程序会留存一份更改向量,并将这个更改向量和数据一起提供给用户界面,当用户修改数据并保存后,我们的应用程序会用用户发送过来的更改向量和本地存储的更改向量进行比较,如果不一致就说明在此期间已经有别的用户改变了数据,那么就会告知用户数据已改变。这种方式我们不需要保留会话,只需要保证每次传输都包含更改向量即可。