使用 SQLite 在 Web 上高效地处理您的所有存储需求。
SQLite 是一款热门的开源轻量级嵌入式关系型数据库管理系统。许多开发者都使用它以结构化且易于使用的方式存储数据。由于其体积小且内存要求低,SQLite 通常被用作移动设备、桌面应用和网络浏览器中的数据库引擎。
SQLite 的一个关键特性是它是一个无服务器数据库,这意味着它不需要单独的服务器进程即可运行。相反,数据库存储在用户设备上的单个文件中,因此可以轻松集成到应用中。
基于 Web Assembly 的 SQLite
有许多基于 Web 汇编 (Wasm) 的非官方 SQLite 版本,可在 Web 浏览器中使用,例如 sql.js。sqlite3 WASM/JS 子项目是首次与 SQLite 项目正式相关联的项目,使该库的 Wasm 版本成为受支持的 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,文件系统访问 API 的一部分) 增强了特殊接口,可实现高性能的数据访问。与现有界面不同,此新界面可提供对文件内容的原位和独占写入权限。此更改以及能够一致读取未刷新的修改以及专用工作器上同步变体的可用性,显著提升了性能并解锁了新用例。
正如您所想,项目目标的最后一点“支持使用可用的 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 大致相当。有时速度会稍慢一些,有时会稍快一些。如需查看所有详细信息,请前往结果页面。
使用入门代码示例
如前所述,使用 Origin 私有文件系统持久化后端的 SQLite Wasm 需要从 Worker 上下文运行。好消息是,该库会自动为您处理所有这些问题,您可以直接在主线程中使用它。
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 网站上查看完整的文档。