RavenDB起步--文档标识符

简介: 在关系型数据库中表一般情况下都会存在主键,这个主键在所在表中是唯一的不可重复的,同样在 RavenDB 中也存在这样的主键,它被成为文档标识符或文档ID。文档ID是由 UTF8 字符串组成的最多 2025 字节长度的全局唯一值。一般来说文档 ID 的组成规则是: 集合名称 + / + 唯一值 ,当然如果你有其他文档 ID 组成的规则也可以使用。下面我们来看一下 RavenDB 生成文档 ID 的策略。

在关系型数据库中表一般情况下都会存在主键,这个主键在所在表中是唯一的不可重复的,同样在 RavenDB 中也存在这样的主键,它被成为文档标识符或文档ID。文档ID是由 UTF8 字符串组成的最多 2025 字节长度的全局唯一值。一般来说文档 ID 的组成规则是: 集合名称 + / + 唯一值 ,当然如果你有其他文档 ID 组成的规则也可以使用。下面我们来看一下 RavenDB 生成文档 ID 的策略。

TIP:RavenDB 的文档 ID 是数据库全局唯一的,这和关系型数据库的主键是所在表唯一不一样。另外文档 ID 建议使用可读性高的字符串,例如:User/Order/001 。

一、语义(外部)文档 ID

生成文档 ID 最常见的方式是用户生成文档 ID,它经常用在生成具有一定意义的 ID 的情况下。实现代码如下:

using Raven.Client.Documents;
var store = new DocumentStore
{
    Urls = new[] { "http://localhost:8080" },
    Database = "Tasks"
};
store.Initialize();
using (var session=store.OpenSession())
{
    var person = new Person
    {
        Name = "张三"
    };
    session.Store(person,"person/zhangsan@demo.com");
    session.SaveChanges();
}

session.Store(person,"person/zhangsan@demo.com");该行代码将文档 ID 设置为 email 地址,这样我们就可以根据用户输入的电子邮件轻松定位到文档。

二、嵌套文档 ID

嵌套文档 ID 是语义文档 ID 的一个特例,比如在一个大型电商系统中,每个 User 都有可能存在多个订单,那么如果我们将每个 User 的所有订单都放在 User 文档中显然是不合理的,正确的做法应该是将订单单独作为一个文档存储。那么这时订单文档的文档 ID 的生成策略就应该是:User文档 ID + / + Order 文档ID

三、客户端生成文档 ID (hilo)

在大部分情况下,我们不希望考虑文档 ID 的生成策略,希望由 RavenDB 来帮我们生成文档 ID。在 RavenDB 中我们可以使用hilo,在我们第一次需要生成 ID 时,向服务器请求保留文档 ID 范围,这时服务器将会确保所提供的范围只对一个客户端使用,然后我们的客户端就可以在给定的范围内安全的生成文档 ID。这种方法是目前最好的生成文档 ID 的方法,可以保证在客户端非常繁忙的情况下扩展,并快速生成大量文档 ID。

这里存在一个问题,当又多个客户端从不同的节点同时向服务端发送保留文档 ID 的请求时,很有可能出现这几个客户端获得打文档 ID 范文是一样的,那么为了解决这个问题各个节点之间会相互通信,如果发现有节点的文档 ID 范围和自己的一样的话,这些节点所生成的文档 ID 后面将会加上节点名称,比如 A 节点和 B 节点同时请求服务端保留文档 ID 范围,这时它俩的文档 ID 范围都是 100-150,那么这两个节点所生成的文档 ID 将会是类似于 User/100-A 和 User/100-B 这样的。

四、服务器端生成文档 ID

虽然 Hilo 可以生成可读性和可预测性较好的文档 ID,但是它需要客户端和服务端合作才能使用,但是如果我们需要手动在 RavenDB Studio 中编写文档或者只指定文档 ID 开头的情况呢?这时我们就可以使用服务端生成文档 ID 策略。比如我们要在 RavenDB Studio中创建一个订单数据,这时我们在 ID 中输入 order/ 然后单击 Save , RavenDB 就会为我们自动生成一个类似于下图的文档 ID。

在这里插入图片描述

同样,使用代码时我们可以在指定文档 ID 时只指定文档 ID 的开头,代码如下:

using Raven.Client.Documents;
var store = new DocumentStore
{
    Urls = new[] { "http://localhost:8080" },
    Database = "Tasks"
};
store.Initialize();
using (var session=store.OpenSession())
{
    var person = new Person
    {
        Name = "张三"
    };
    session.Store(person, "user/");
    session.SaveChanges();
}

运行下面代码后,在 RavenDB Studio 中查看 person 文档,新添加的数据如下:

在这里插入图片描述

五、Identity 生成文档 ID 策略

如果在开发中需要生成连续的文档 ID ,那么我们可以使用 Identity 生成文档 ID 策略。Identity 每次生成文档 ID 都需要向服务器发送请求。Identity 生成文档 ID 和服务器端生成文档 ID 很相似,但是不是使用 / 而是使用 | 来作为结尾生成 ID。我们在  RavenDB Studio 的 ID 中输入:order| 即可使用 Identity 生成 ID。生成结果如下图:

在这里插入图片描述

这个策略存在一个问题,如果我们尝试使用 ID 保存文档并且保存失败,值仍然会递增。因此,即使 Identity 生成连续数字,如果事务已回滚,它仍可能会跳过标识符。

同时在分布式环境中,这种策略需要我们防止竞争,例如两个客户端在两个不同的服务器上生成相同的 Identity ,生成新 Identity 的部分过程需要节点相互协调。这意味着我们需要通过网络与集群中的其他成员通信,以确保我们拥有 Identity 的下一个值。这会增加保存带有 Identity 的新文档的成本。更糟糕的是,在故障情况下,我们可能无法与集群中足够数量的节点进行通信。这意味着我们也将无法生成请求的 Identity。

TIP:除非有明确的要求必须使用连续的 ID,否则这种策略不予考虑。

六、总结

我们已经讨论了很多生成文档标识符的选项,每个选项都有自己的行为和成本,各种方法之间也存在性能差异。

RavenDB 通过将文档 ID 存储在 B+Tree 中来跟踪它们。如果文档 ID 非常大,则意味着 RavenDB 可以在给定空间中存储更少的文档 ID。

  1. hilo 生成的文档 ID 在词法上可排序,在大多数情况下,我们可以获得优质的树和非常有效的搜索,并且它还生成最易读的内容;
  2. 使用斜线的服务器端方法在存储适用性方面最佳值。比 hilo 生成的 ID 要大一些,但就底层存储而言,它是按词法排序的,以及时可预测的,从而弥补了这一点。它非常适合大型批处理作业,并且在其中包含许多额外的优化;
  3. 语义生成的 ID 是未排序的,RavenDB 可以轻松处理大量带有语义标识符的文档,对于性能来说也没什么大问题;
  4. Identity 生成文档 ID ,需要网络请求才能生成下一个值,如果节点无法与集群中的大多数节点通信,这个方法将变得不可用。
目录
相关文章
|
8月前
|
XML 监控 中间件
SAP 产品线中写法很接近,容易混淆的几个名称
SAP 产品线中写法很接近,容易混淆的几个名称
44 0
|
8月前
|
SQL 数据库
SAP ABAP OData 服务如何支持 $select 有选择性地仅读取部分模型字段值试读版
SAP ABAP OData 服务如何支持 $select 有选择性地仅读取部分模型字段值试读版
53 0
|
12月前
|
存储
优秀开源项目推荐之--文档库bookstack
优秀开源项目推荐之--文档库bookstack
|
存储 SQL 安全
odoo 开发入门教程系列-模型和基本字段
odoo 开发入门教程系列-模型和基本字段
153 0
|
数据库
通过互联网搜索接口更新拼写语法库的设计
通过互联网搜索接口更新拼写语法库的设计
51 0
|
NoSQL Java 程序员
Spring改变版本号命名规则:此举对非英语国家很友好
Spring改变版本号命名规则:此举对非英语国家很友好
Spring改变版本号命名规则:此举对非英语国家很友好
|
JavaScript 前端开发 API
前端工程化必备,语义化版本号扫盲,支持任意版本号位数的比较方法
因为最近在做 Node 相关的项目,涉及到版本号的处理,根据版本号大小做升级 js 处理的,而因为多加了一位数,导致线上的 js 不能升级。 所以只能重写一个支持任意位数的版本号对比方法。 顺便先来一个语义化版本号的扫盲吧。
270 0
|
JavaScript 数据库
RavenDB起步--使用 RavenDB Studio
上一篇文章我们讲解了 RavenDB 的安装以及示例数据库的创建,并且其中涉及到了 RavenDB Stuido 的使用,但是只是简单的讲解了一下。那么在这篇文章中我将带领大家来具体的学习 如何在 RavenDB Studio 中实现增删改查。
122 0
|
存储 JSON Linux
RavenDB起步--安装以及示例数据库
本篇是 RavenDB 起步阶段的首篇文章,我将会在这篇文章里讲解如何安装 RavenDB 以及如何创建实例数据库。下面就让我们开始吧!
103 0
RavenDB起步--安装以及示例数据库
如何使用配置的方式修改SAP C4C UI的字段标签,以及背后的工作原理
I was asked by one partner that it is expected to adapt the label of “New” button into “Add”, and change the text of first menu item from “Add” to “From Contact”.
如何使用配置的方式修改SAP C4C UI的字段标签,以及背后的工作原理