Deno KV 快速入门
Deno KV 是直接内置于 Deno 运行时中的键值数据库,可在 Deno.Kv
命名空间中使用。它可用于多种数据存储用例,但在存储受益于极快读写速度的简单数据结构方面表现出色。Deno KV 可在 Deno CLI 和 Deno Deploy 上使用。
Deno KV 仍在开发中,可能会有所变化。要使用它,您必须向 Deno 传递 --unstable-kv
标志。
让我们一起来了解 Deno KV 的主要功能。
打开数据库 Jump to heading
在您的 Deno 程序中,您可以使用 Deno.openKv()
获取 KV 数据库的引用。您可以传入一个可选的文件系统路径来存储您的数据库,否则将根据您脚本的当前工作目录为您创建一个数据库。
const kv = await Deno.openKv();
创建、更新和读取键值对 Jump to heading
Deno KV 中的数据以键值对的形式存储,与 JavaScript 对象字面量或 Map 的属性非常相似。键表示为 JavaScript 类型数组,例如 string
、number
、bigint
或 boolean
。值可以是任意 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);
get
和 list
操作都返回一个具有以下属性的 KvEntry 对象
key
- 您用于设置值的数组键value
- 您为此键设置的 JavaScript 对象versionstamp
- 一个生成的值,用于确定键是否已更新。
set
操作也用于更新给定键已存在的对象。当键的值更新时,其 versionstamp
将变为新的生成值。
列出多个键值对 Jump to heading
要获取有限数量键的值,您可以使用 kv.getMany()
。传入多个键作为参数,您将收到每个键对应的值数组。请注意,如果给定键不存在值,则值和版本戳可能为 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()
按该顺序返回。
读取操作可以在强一致性模式或最终一致性模式下执行。强一致性模式保证读取操作将返回最新写入的值。最终一致性模式可能会返回一个过时值,但速度更快。相比之下,写入操作始终在强一致性模式下执行。
删除键值对 Jump to heading
您可以使用 kv.delete()
从数据库中删除一个键。如果给定键没有找到值,则不执行任何操作。
const kv = await Deno.openKv();
await kv.delete(["preferences", "alan"]);
原子事务 Jump to heading
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 事务的信息。
通过二级索引改进查询 Jump to heading
二级索引通过多个键存储相同的数据,从而可以更简单地查询所需数据。假设我们需要能够通过用户名和电子邮件访问用户偏好设置。为此,您可以提供一个函数来封装保存偏好设置的逻辑,以创建两个索引。
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 中的更新 Jump to heading
您还可以使用 kv.watch()
监听 Deno KV 的更新,它将发出您提供的键的新值或多个值。在下面的聊天示例中,我们监听键 ["last_message_id", roomId]
上的更新。我们检索 messageId
,然后将其与 kv.list()
一起使用,从 seen
和 messageId
中获取所有新消息。
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 watch 的信息。
生产环境使用 Jump to heading
Deno KV 可在 Deno Deploy 上用于实时应用程序。在生产环境中,Deno KV 由 Apple 创建的开源键值存储 FoundationDB 提供支持。
在 Deploy 上运行使用 KV 的 Deno 程序无需额外配置 - 当您的代码需要时,将为您预置一个新的 Deploy 数据库。在此处了解更多关于 Deno Deploy 上的 Deno KV 的信息。
测试 Jump to heading
默认情况下,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 文档中关于该主题的内容。
下一步 Jump to heading
到目前为止,您才刚刚开始接触 Deno KV。请务必查看我们关于 Deno KV 键空间的指南,以及在此处查看教程和示例应用程序的集合。