使用 SQLite 在 Web 上高效地处理您的所有存储需求。
SQLite 是一种热门的开源轻量级嵌入式关系型数据库管理系统。许多开发者都使用它以结构化且易于使用的方式存储数据。由于其体积小且内存要求低,SQLite 通常被用作移动设备、桌面应用和网络浏览器中的数据库引擎。
SQLite 的一个关键特性是它是一个无服务器数据库,这意味着它不需要单独的服务器进程即可运行。相反,数据库存储在用户设备上的单个文件中,因此可以轻松集成到应用中。
基于 Web Assembly 的 SQLite
有许多基于 Web 汇编 (Wasm) 的非官方 SQLite 版本,可在 Web 浏览器中使用,例如 sql.js。sqlite3 WASM/JS 子项目是与 SQLite 项目正式关联的首要项目,因此该库的 Wasm build 成为了受支持的 SQLite 交付项系列的成员。该项目的具体目标包括:
- 绑定一个低级别的 sqlite3 API,在使用方面尽可能接近 C API。
- 一种面向对象的更高层级 API,更类似于 sql.js 和 Node.js 样式的实现,直接对应低层级 API。此 API 必须从低级别 API 所在的线程使用。
- 基于 Worker 的 API,它通过 worker 消息与之前的 API 通信。此 API 适用于在主线程中使用,将较低级别的 API 安装在 Worker 线程中,并通过 Worker 消息与它们通信。
- Worker API 的基于 Promise 的变体,可将跨线程通信方面完全隐藏起来,不对用户显示。
- 支持使用可用的 JavaScript API(包括 Origin Private File System [OPFS])进行永久性客户端存储。
将 SQLite Wasm 与 Origin 私有文件系统持久性后端搭配使用
通过 npm 安装库
使用以下命令从 npm 安装 @sqlite.org/sqlite-wasm 软件包:
npm install @sqlite.org/sqlite-wasm
源私有文件系统
源私有文件系统(OPFS,File System Access API 的一部分)通过一个可以实现非常高性能的数据访问的特殊 Surface 得到增强。与现有界面不同,此新界面可提供对文件内容的原位和独占写入权限。此更改以及能够一致读取未刷新的修改以及专用工作器上同步变体的可用性,显著提升了性能并解锁了新用例。
正如您所想,项目目标的最后一点“支持使用可用的 JavaScript API 进行持久性客户端存储”对将数据持久化到数据库文件有严格的性能要求。这正是 Origin 私有文件系统(更具体地说,是 FileSystemFileHandle
对象的 createSyncAccessHandle()
方法)发挥作用的地方。此方法会返回一个 promise,该 promise 会解析为 FileSystemSyncAccessHandle
对象,可用于同步读取和写入文件。此方法的同步性质可带来性能优势,因此它只能在适用于原始私有文件系统中文件的专用 Web Worker 内使用,因此无法阻塞主线程。
设置所需的标头
下载的 SQLite Wasm 归档文件中包含 sqlite3.js
和 sqlite3.wasm
文件,这些文件构成了 sqlite3 WASM/JS build。jswasm
目录包含核心 sqlite3 交付项,顶级目录包含演示和测试应用。浏览器不会通过 file://
网址提供 Wasm 文件,因此您使用此方法构建的任何应用都需要 Web 服务器,并且该服务器在提供文件时必须在响应中包含以下标头:
Cross-Origin-Opener-Policy
设置为same-origin
指令,该指令会将浏览上下文完全隔离到同源文档。跨源文档不会在同一浏览上下文中加载。Cross-Origin-Embedder-Policy
设置为require-corp
指令,使文档只能加载同一来源的资源或明确标记为可从其他来源加载的资源。
之所以使用这些头文件,是因为 SQLite Wasm 依赖于 SharedArrayBuffer
,而设置这些头文件是其安全要求的一部分。
如果您使用 DevTools 检查流量,应该会看到以下信息:
Speedtest
SQLite 团队对其 WebAssembly 实现与已废弃的 Web SQL 进行了一些基准测试。这些基准测试结果表明,SQLite Wasm 的速度通常与 Web SQL 大致相当。有时速度会稍慢一些,有时会稍快一些。如需查看所有详细信息,请前往结果页面。
入门代码示例
如前所述,包含源私有文件系统持久性后端的 SQLite Wasm 需要从工作器上下文运行。好消息是,该库会自动为您处理所有这些事项,您可以直接在主线程中使用它。
import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';
(async () => {
try {
console.log('Loading and initializing SQLite3 module...');
const promiser = await new Promise((resolve) => {
const _promiser = sqlite3Worker1Promiser({
onready: () => {
resolve(_promiser);
},
});
});
console.log('Done initializing. Running demo...');
let response;
response = await promiser('config-get', {});
console.log('Running SQLite3 version', response.result.version.libVersion);
response = await promiser('open', {
filename: 'file:worker-promiser.sqlite3?vfs=opfs',
});
const { dbId } = response;
console.log(
'OPFS is available, created persisted database at',
response.result.filename.replace(/^file:(.*?)\?vfs=opfs$/, '$1'),
);
await promiser('exec', { dbId, sql: 'CREATE TABLE IF NOT EXISTS t(a,b)' });
console.log('Creating a table...');
console.log('Insert some data using exec()...');
for (let i = 20; i <= 25; ++i) {
await promiser('exec', {
dbId,
sql: 'INSERT INTO t(a,b) VALUES (?,?)',
bind: [i, i * 2],
});
}
console.log('Query data with exec()');
await promiser('exec', {
dbId,
sql: 'SELECT a FROM t ORDER BY a LIMIT 3',
callback: (result) => {
if (!result.row) {
return;
}
console.log(result.row);
},
});
await promiser('close', { dbId });
} catch (err) {
if (!(err instanceof Error)) {
err = new Error(err.result.message);
}
console.error(err.name, err.message);
}
})();
演示
如需查看上述代码的实际运作情况,请参阅演示。 请务必查看 Glitch 上的源代码。请注意,下面的嵌入式版本如何使用 OPFS 后端,但当您在单独的标签页中打开演示时,它会使用 OPFS 后端。
调试源私有文件系统
如需调试 SQLite Wasm 的来源私有文件系统输出,请使用 OPFS Explorer Chrome 扩展程序。
安装扩展程序后,打开 Chrome 开发者工具,选择 OPFS Explorer 标签页,然后即可检查 SQLite Wasm 写入源私有文件系统的内容。
如果您在 DevTools 的 OPFS Explorer 窗口中选择任何文件,则可以将其保存到本地磁盘。然后,您可以使用 SQLite Viewer 等应用检查数据库,以确保 SQLite Wasm 确实能按承诺运行。
获取帮助和提供反馈
SQLite Wasm 由 SQLite 社区开发和维护。您可以搜索支持论坛并在其中发帖,以获取帮助和提供反馈。您可以在 SQLite 网站上查看完整的文档。