兰 亭 墨 苑
期货 · 量化 · AI · 终身学习
首页
归档
编辑文章
标题 *
URL 别名 *
内容 *
(支持 Markdown 格式)
下面我将为您概述 Durable Objects 存储 API 的用法,并结合文档内容进行解释。 ### 核心概述 Durable Objects 存储 API 为每个对象实例提供了一个**私有的、事务性的、强一致性**的存储空间。 这意味着数据是安全的、最新的,并且操作是原子的(要么全部成功,要么全部失败)。 根据文档,存储后端主要有两种: 1. **KV (键值对) 模式**:这是传统的存储方式。 2. **SQLite 模式**:这是 **Cloudflare 推荐的新模式**,它在对象内部嵌入了一个完整的 SQLite 数据库,不仅支持键值对操作,还支持功能强大的 SQL 查询。 无论使用哪种模式,你都通过 `this.state.storage` (在旧版 Worker 中) 或 `this.ctx.storage` (在新版模块 Worker 中) 来访问存储 API。 --- ### 1. 键值对 (KV) API 用法 这些是最常用、最基础的操作,在 SQLite 和 KV 两种模式下都可用。 #### `put()` - 存储或更新数据 此方法用于存储一个或多个键值对。 如果键已存在,其值将被覆盖。 * **单个存储**: ```javascript // 存储一个字符串值 await this.ctx.storage.put("username", "alice"); // 存储一个数字和对象 await this.ctx.storage.put("loginCount", 15); await this.ctx.storage.put("profile", { email: "test@example.com", plan: "pro" }); ``` * **批量存储**: 可以一次性存储多个键值对,最多支持 128 个。 ```javascript await this.ctx.storage.put({ username: "bob", loginCount: 1, lastLogin: Date.now() }); ``` #### `get()` - 读取数据 此方法用于读取一个或多个键的值。 如果键不存在,则返回 `undefined`。 * **单个读取**: ```javascript let username = await this.ctx.storage.get("username"); // 返回 "alice" 或 undefined let profile = await this.ctx.storage.get("profile"); // 返回存储的对象 ``` * **批量读取**: 一次性读取多个键,返回一个 `Map` 对象。 任何不存在的键都不会出现在返回的 Map 中。 最多支持 128 个键。 ```javascript let data = await this.ctx.storage.get(["username", "loginCount", "nonexistentKey"]); // data 是一个 Map: // data.get("username") -> "bob" // data.get("loginCount") -> 1 // data.has("nonexistentKey") -> false ``` #### `delete()` - 删除数据 删除一个或多个键值对。 * **单个删除**: 如果键存在并被成功删除,返回 `true`,否则返回 `false`。 ```javascript let wasDeleted = await this.ctx.storage.delete("old-key"); ``` * **批量删除**: 返回成功删除的键值对的数量。 最多支持 128 个键。 ```javascript let deletedCount = await this.ctx.storage.delete(["temp-key-1", "temp-key-2"]); ``` #### `list()` - 列出键值对 返回对象中存储的所有或部分键值对,结果是一个 `Map`。 **警告**: 如果不加任何选项直接调用 `list()`,它会尝试将对象中的**所有数据**加载到内存中,这可能导致超出内存限制。 * **常用选项**: * `prefix`: 只列出以特定字符串开头的键。 * `limit`: 限制返回的键值对数量。 * `start` / `startAfter`: 从哪个键开始(或之后)列出。 * `reverse`: `true` 表示降序排列。 * **示例**: ```javascript // 获取所有以 "user:" 开头的键值对 let userEntries = await this.ctx.storage.list({ prefix: "user:" }); // 获取前 10 个键值对 let firstTen = await this.ctx.storage.list({ limit: 10 }); ``` #### `deleteAll()` - 删除所有数据 清空该 Durable Object 实例中的所有数据。 在 SQLite 模式下,此操作是原子的;在旧的 KV 模式下,如果中途失败可能只删除了一部分。 ```javascript await this.ctx.storage.deleteAll(); ``` --- ### 2. SQL API 用法 (仅限 SQLite 模式) 这是 SQLite 模式独有的强大功能,允许你执行原生 SQL 查询。 通过 `this.ctx.storage.sql` 访问。 #### `sql.exec()` - 执行 SQL 查询 这是核心方法,用于执行任何 SQL 语句。 * **参数**: 1. `query`: 包含 SQL 语句的字符串。 可以用 `?` 作为参数占位符。 2. `...bindings`: 传递给 `?` 占位符的实际值。 * **返回值**: 返回一个可迭代的 `cursor` 对象,你可以用它来遍历查询结果。 * **示例**: ```javascript // 在构造函数中初始化表结构 constructor(ctx, env) { super(ctx, env); this.sql = this.ctx.storage.sql; // 如果表不存在,就创建它 this.sql.exec(` CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT, email TEXT )`); } // --- 在其他方法中使用 --- // 插入数据 (使用参数绑定) this.sql.exec("INSERT INTO users (name, email) VALUES (?, ?)", "Charlie", "charlie@example.com"); // 查询数据并遍历结果 let cursor = this.sql.exec("SELECT * FROM users WHERE name LIKE ?", "C%"); for (const row of cursor) { console.log(row.id, row.name); // 输出: 1 Charlie } // 将查询结果直接转为数组 let allUsers = this.sql.exec("SELECT * FROM users").toArray(); // allUsers 是一个对象数组: [{ id: 1, name: 'Charlie', ... }] ``` --- ### 3. 事务 (Transactions) 的重要概念 Durable Objects 的一个关键优势是其内置的事务性保证。 * **自动事务**: 文档指出,显式的 `transaction()` API 在很多情况下已不再是必需的。 系统会自动将操作打包处理: * **自动写入合并**: 如果你连续调用多个 `put()` 或 `delete()` 而中间没有 `await`,它们会被自动合并成一个原子操作提交。 * **读写原子性**: 当你执行一个 `await` 读取操作(如 `get()`)时,系统会自动阻止其他事件并发执行,直到读取完成。 因此,“先读后写”的模式(`await get()`, 然后 `put()`)天然就是事务性的和安全的。 这个特性极大地简化了代码,让你无需手动管理锁和事务就能编写出正确、无竞态条件的代码。
配图 (可多选)
选择新图片文件或拖拽到此处
标签
更新文章
删除文章