deno.com
本页内容

Deno KV 快速入门

Deno KV 是一个 键值数据库,直接构建到 Deno 运行时中,可在 Deno.Kv 命名空间 中使用。它可用于多种数据存储用例,但在存储受益于极速读取和写入的简单数据结构方面表现出色。Deno KV 在 Deno CLI 和 Deno Deploy 上均可用。

让我们一起了解 Deno KV 的主要功能。

打开数据库 跳转到标题

在您的 Deno 程序中,您可以使用 Deno.openKv() 获取对 KV 数据库的引用。您可以传入一个可选的文件系统路径,以指定您希望存储数据库的位置,否则将根据脚本的当前工作目录为您创建一个数据库。

const kv = await Deno.openKv();

创建、更新和读取键值对 跳转到标题

Deno KV 中的数据以键值对的形式存储,非常类似于 JavaScript 对象字面量或 Map 的属性。 表示为 JavaScript 类型数组,例如 stringnumberbigintboolean。值可以是任意 JavaScript 对象。在此示例中,我们创建一个表示用户 UI 偏好的键值对,并使用 kv.set() 保存它。

const kv = await Deno.openKv();

const prefs = {
  username: "ada",
  theme: "dark",
  language: "en-US",
};

const result = await kv.set(["preferences", "ada"], prefs);

设置键值对后,您可以使用 kv.get() 从数据库中读取它

const entry = await kv.get(["preferences", "ada"]);
console.log(entry.key);
console.log(entry.value);
console.log(entry.versionstamp);

getlist 操作 都返回一个 KvEntry 对象,其中包含以下属性

  • key - 您用于设置值的数组键
  • value - 您为此键设置的 JavaScript 对象
  • versionstamp - 用于确定键是否已更新的生成值。

set 操作也用于更新已存在于给定键的对象。当键的值更新时,其 versionstamp 将更改为新的生成值。

列出多个键值对 跳转到标题

要获取有限数量的键的值,您可以使用 kv.getMany()。传入多个键作为参数,您将收到每个键的值数组。请注意,如果给定键不存在值,值和 versionstamp 可能为 null

const kv = await Deno.openKv();
const result = await kv.getMany([
  ["preferences", "ada"],
  ["preferences", "grace"],
]);
result[0].key; // ["preferences", "ada"]
result[0].value; // { ... }
result[0].versionstamp; // "00000000000000010000"
result[1].key; // ["preferences", "grace"]
result[1].value; // null
result[1].versionstamp; // null

通常,从共享给定前缀的所有键中检索键值对列表非常有用。可以使用 kv.list() 完成此类操作。在此示例中,我们获取共享 "preferences" 前缀的键值对列表。

const kv = await Deno.openKv();
const entries = kv.list({ prefix: ["preferences"] });
for await (const entry of entries) {
  console.log(entry.key); // ["preferences", "ada"]
  console.log(entry.value); // { ... }
  console.log(entry.versionstamp); // "00000000000000010000"
}

返回的键按前缀后键的下一个组件以字典顺序排序。因此,具有以下键的 KV 对

  • ["preferences", "ada"]
  • ["preferences", "bob"]
  • ["preferences", "cassie"]

将由 kv.list() 按该顺序返回。

读取操作可以在 强一致性或最终一致性模式 下执行。强一致性模式保证读取操作将返回最近写入的值。最终一致性模式可能会返回过时的值,但速度更快。相比之下,写入始终以强一致性模式执行。

删除键值对 跳转到标题

您可以使用 kv.delete() 从数据库中删除键。如果找不到给定键的值,则不执行任何操作。

const kv = await Deno.openKv();
await kv.delete(["preferences", "alan"]);

原子事务 跳转到标题

Deno KV 能够执行 原子事务,这使您可以有条件地一次执行一个或多个数据操作。在以下示例中,我们仅在首选项对象尚未创建时才创建新对象。

const kv = await Deno.openKv();

const key = ["preferences", "alan"];
const value = {
  username: "alan",
  theme: "light",
  language: "en-GB",
};

const res = await kv.atomic()
  .check({ key, versionstamp: null }) // `null` versionstamps mean 'no value'
  .set(key, value)
  .commit();
if (res.ok) {
  console.log("Preferences did not yet exist. Inserted!");
} else {
  console.error("Preferences already exist.");
}

在此处了解有关 Deno KV 中事务的更多信息 here

使用二级索引改进查询 跳转到标题

二级索引 通过多个键存储相同的数据,从而可以更轻松地查询您需要的数据。假设我们需要能够通过用户名和电子邮件访问用户偏好。为了实现这一点,您可以提供一个函数来包装逻辑,以保存偏好设置以创建两个索引。

const kv = await Deno.openKv();

async function savePreferences(prefs) {
  const key = ["preferences", prefs.username];

  // Set the primary key
  const r = await kv.set(key, prefs);

  // Set the secondary key's value to be the primary key
  await kv.set(["preferencesByEmail", prefs.email], key);

  return r;
}

async function getByUsername(username) {
  // Use as before...
  const r = await kv.get(["preferences", username]);
  return r;
}

async function getByEmail(email) {
  // Look up the key by email, then second lookup for actual data
  const r1 = await kv.get(["preferencesByEmail", email]);
  const r2 = await kv.get(r1.value);
  return r2;
}

在此处的手册中了解有关 二级索引的更多信息

在 Deno KV 中监视更新 跳转到标题

您还可以使用 kv.watch() 监听来自 Deno KV 的更新,这将发出您提供的键或键的新值或多个值。在下面的聊天示例中,我们监视键 ["last_message_id", roomId] 上的更新。我们检索 messageId,然后将其与 kv.list() 一起使用,以从 seenmessageId 中获取所有新消息。

let seen = "";
for await (const [messageId] of kv.watch([["last_message_id", roomId]])) {
  const newMessages = await Array.fromAsync(kv.list({
    start: ["messages", roomId, seen, ""],
    end: ["messages", roomId, messageId, ""],
  }));
  await websocket.write(JSON.stringify(newMessages));
  seen = messageId;
}

在此处了解有关 使用 Deno KV 监视的更多信息

生产环境使用 跳转到标题

Deno KV 可在 Deno Deploy 上的实时应用程序中使用。在生产环境中,Deno KV 由 FoundationDB 提供支持,FoundationDB 是 Apple 创建的开源键值存储。

无需其他配置 即可在 Deploy 上运行使用 KV 的 Deno 程序 - 当您的代码需要时,将为您预配一个新的 Deploy 数据库。在此处了解有关 Deno Deploy 上的 Deno KV 的更多信息 here

测试 跳转到标题

默认情况下,Deno.openKv() 基于调用它的脚本运行的路径创建或打开持久存储。这通常不适用于测试,测试需要多次连续运行时产生相同的行为。

要测试使用 Deno KV 的代码,您可以使用特殊参数 ":memory:" 来创建临时的 Deno KV 数据存储。

async function setDisplayName(
  kv: Deno.Kv,
  username: string,
  displayname: string,
) {
  await kv.set(["preferences", username, "displayname"], displayname);
}

async function getDisplayName(
  kv: Deno.Kv,
  username: string,
): Promise<string | null> {
  return (await kv.get(["preferences", username, "displayname"]))
    .value as string;
}

Deno.test("Preferences", async (t) => {
  const kv = await Deno.openKv(":memory:");

  await t.step("can set displayname", async () => {
    const displayName = await getDisplayName(kv, "example");
    assertEquals(displayName, null);

    await setDisplayName(kv, "example", "Exemplary User");

    const displayName = await getDisplayName(kv, "example");
    assertEquals(displayName, "Exemplary User");
  });
});

这是可行的,因为在本地开发运行时,Deno KV 由 SQLite 提供支持。就像内存中的 SQLite 数据库一样,可以同时存在多个临时的 Deno KV 存储,而不会相互干扰。有关特殊数据库寻址模式的更多信息,请参阅 关于该主题的 SQLite 文档

下一步 跳转到标题

此时,您才刚刚开始了解 Deno KV 的皮毛。请务必查看我们的 Deno KV 键空间 指南,以及此处的 教程和示例应用程序 集合。

您找到所需的内容了吗?

隐私政策