Skip to main content
Bun 原生实现了高性能的 SQLite3 驱动。要使用它,从内置的 bun:sqlite 模块导入。
db.ts
该 API 是同步且快速的。感谢 better-sqlite3 及其贡献者为 bun:sqlite 的 API 提供了灵感。 特性包括:
  • 事务
  • 参数(命名和位置)
  • 预编译语句
  • 数据类型转换(BLOB 变为 Uint8Array
  • 无需 ORM 即可将查询结果映射到类 - query.as(MyClass)
  • 任何 SQLite JavaScript 驱动中最快的性能
  • bigint 支持
  • 单次调用 database.run(query) 支持多语句查询(例如 SELECT 1; SELECT 2;
bun:sqlite 模块在读取查询方面比 better-sqlite3 快大约 3-6 倍,比 deno.land/x/sqlite 快 8-9 倍。每个驱动都针对 Northwind Traders 数据集进行了基准测试。查看并运行基准测试源码
Bun、better-sqlite3 和 deno.land/x/sqlite 的 SQLite 基准测试

在配备 64GB 内存的 M1 MacBook Pro 上运行 macOS 12.3.1 进行基准测试


数据库

要打开或创建 SQLite3 数据库:
db.ts
要打开内存数据库:
db.ts
要以 readonly 模式打开:
db.ts
如果文件不存在则创建数据库:
db.ts

严格模式

默认情况下,bun:sqlite 要求绑定参数时包含 $:@ 前缀,并且不会在参数缺失时抛出错误。 要在参数缺失时抛出错误并允许不带前缀的绑定,在 Database 构造函数上设置 strict: true
db.ts

通过 ES 模块导入加载

你也可以使用导入属性加载数据库。
db.ts
这等同于以下方式:
db.ts

.close(throwOnError: boolean = false)

要关闭数据库连接但允许现有查询完成,调用 .close(false)
db.ts
要关闭数据库并在有任何待处理查询时抛出错误,调用 .close(true)
db.ts
close(false) 在数据库被垃圾回收时自动调用。多次调用是安全的,但在第一次之后就没有效果了。

using 语句

using 语句在块退出时关闭数据库连接。
db.ts

.serialize()

bun:sqlite 支持 SQLite 内置的序列化反序列化数据库到内存的机制。
db.ts
内部调用 sqlite3_serialize.serialize()

.query()

使用 Database 实例上的 db.query() 方法准备 SQL 查询。结果是一个 Statement 实例,该实例会被缓存在 Database 实例上。查询不会被执行。
db.ts
“缓存”意味着什么?缓存指的是编译后的预编译语句(SQL 字节码),而不是查询结果。当你多次使用相同的 SQL 字符串调用 db.query() 时,Bun 会返回相同的缓存 Statement 对象,而不是重新编译 SQL。使用不同的参数值重复使用缓存的语句是安全的:
当你想要一个不被缓存的新 Statement 实例时,请使用 .prepare() 而不是 .query(),例如当你动态生成 SQL 且不想用一次性查询填满缓存时。

WAL 模式

SQLite 支持预写日志模式(WAL),这可以显著提高性能,尤其是在有多个并发读取器和单个写入器时。建议大多数应用程序启用 WAL 模式。 要启用 WAL 模式,在应用程序开头运行此 pragma 查询:
db.ts
在 WAL 模式下,对数据库的写入直接写入到单独的文件中,称为”WAL 文件”(-wal)。还会创建一个共享内存索引文件(-shm)用于读取协调。WAL 文件随后会整合到主数据库文件中。可以将其视为待处理写入的缓冲区。有关更详细的概述,请参考 SQLite 文档

WAL 附属文件清理

当使用基于文件的数据库的 WAL 模式时,SQLite 会在你的数据库旁边创建两个附属文件:预写日志(-wal)和共享内存索引(-shm)。这些文件是否在 .close() 后自动移除取决于你的平台:
  • macOS:Bun 使用系统提供的 SQLite,Apple 构建了持久化 WAL。-wal-shm 文件在关闭后会持久存在。这不是 bug——这是 Apple 配置系统 SQLite 的方式。
  • LinuxWindows:Bun 静态链接自己的 SQLite 构建,遵循上游默认值。当没有其他连接打开时,附属文件通常会被移除
要确保在所有平台上清理附属文件,在关闭之前禁用 WAL 持久化并运行截断检查点:
db.ts

语句

Statement 是一个_预编译查询_,意味着它已被解析并编译为高效的二进制形式。它可以被执行多次。 使用 Database 实例上的 .query 方法创建语句。
db.ts
查询可以包含参数。它们可以是数字型(?1)或命名型($param:param@param)。
db.ts
在执行查询时,值会绑定到这些参数。一个 Statement 可以通过几种不同的方法执行,每种方法以不同的形式返回结果。

绑定值

要向语句绑定值,向 .all().get().run().values() 方法传递一个对象。
db.ts
你也可以使用位置参数进行绑定:
db.ts

strict: true 允许不带前缀地绑定值

默认情况下,在向命名参数绑定值时,$:@ 前缀是包含的。要在没有这些前缀的情况下绑定,在 Database 构造函数中使用 strict 选项。
db.ts

.all()

使用 .all() 运行查询并以对象数组形式获取结果。
db.ts
内部调用 sqlite3_reset 并重复调用 sqlite3_step,直到返回 SQLITE_DONE

.get()

使用 .get() 运行查询并以对象形式获取第一个结果。
db.ts
内部调用 sqlite3_reset 后跟 sqlite3_step,直到不再返回 SQLITE_ROW。如果查询没有返回行,则返回 null

.run()

使用 .run() 运行查询并获取包含执行元数据的对象。这适用于模式修改查询(如 CREATE TABLE)或批量写入操作。
db.ts
内部调用 sqlite3_reset 并调用 sqlite3_step 一次。当你不在乎结果时,不需要遍历所有行。 lastInsertRowid 属性是最后插入到数据库中的行的 ID。changes 属性是受查询影响的行数。

.as(Class) - 将查询结果映射到类

使用 .as(Class) 运行查询并获取作为类实例的结果。该类的 methods、getters 和 setters 在每个行上可用。
db.ts
作为性能优化,类的构造函数不会被调用,默认初始化器不会运行,私有字段不可访问。这更像是 Object.create 而不是 new:类的 prototype 被赋值给对象,因此其 methods、getters 和 setters 可以工作。 数据库列作为属性设置在类实例上。

.iterate() (@@iterator)

使用 .iterate() 运行查询并增量返回结果。这适用于希望逐行处理结果而不将所有结果加载到内存中的大数据集。
db.ts
你也可以使用 @@iterator 协议:
db.ts

.values()

使用 values() 运行查询并获取所有结果作为数组的数组。
db.ts
内部调用 sqlite3_reset 并重复调用 sqlite3_step,直到返回 SQLITE_DONE

.finalize()

使用 .finalize() 销毁 Statement 并释放与其关联的任何资源。一旦终结,Statement 就不能再被执行。通常,垃圾回收器会为你做这件事,但在性能敏感的应用程序中,显式终结可能很有用。
db.ts

.toString()

Statement 实例上调用 toString() 会打印扩展后的 SQL 查询。这有助于调试。
db.ts
内部调用 sqlite3_expanded_sql。参数使用最近绑定的值进行扩展。

参数

查询可以包含参数。它们可以是数字型(?1)或命名型($param:param@param)。在执行查询时将值绑定到这些参数:
query.ts
编号(位置)参数也可以使用:
db.ts

整数

SQLite 支持有符号 64 位整数,但 JavaScript 只支持有符号 52 位整数或使用 bigint 的任意精度整数。 bigint 输入在所有地方都受支持,但默认情况下 bun:sqlitenumber 类型返回整数。如果你需要处理大于 2^53 的整数,在创建 Database 实例时将 safeIntegers 选项设置为 true。这还会验证传递给 bun:sqlitebigint 值不超过 64 位。

safeIntegers: true

safeIntegerstrue 时,bun:sqlitebigint 类型返回整数:
db.ts
safeIntegerstrue 时,如果绑定参数中的 bigint 值超过 64 位,bun:sqlite 会抛出错误:
db.ts

safeIntegers: false(默认)

safeIntegersfalse 时,bun:sqlitenumber 类型返回整数,并截断超过 53 位的任何位:
db.ts

事务

事务会_原子性_地执行多个查询:要么全部成功,要么全都不成功。使用 db.transaction() 方法创建事务:
db.ts
还没有猫被插入。db.transaction() 返回一个新函数(insertCats),它_包装_了执行查询的函数。 要执行事务,调用此函数。参数会传递给包装的函数,并且包装的函数的返回值由事务函数返回。包装的函数还可以访问 this 上下文,其定义由事务执行的位置决定。
db.ts
驱动会在调用 insertCats 时自动开始一个事务,并在包装的函数返回时提交。如果抛出异常,事务会回滚。异常会正常传播;不会被捕获。
嵌套事务 — 事务函数可以从其他事务函数内部调用。此时,内部事务会变成一个保存点
db.ts
事务还提供了 deferredimmediateexclusive 版本。

.loadExtension()

要加载 SQLite 扩展,在你的 Database 实例上调用 .loadExtension(name)
db.ts
macOS 用户 默认情况下,macOS 自带 Apple 专有的 SQLite 构建,不支持扩展。要使用扩展,安装一个原版的 SQLite 构建。
terminal
要将 bun:sqlite 指向新构建,在创建任何 Database 实例之前调用 Database.setCustomSQLite(path)。(在其他操作系统上,这是一个无操作。)传递 SQLite .dylib 文件的路径,_不是_可执行文件。使用最新版的 Homebrew,路径类似于 /opt/homebrew/Cellar/sqlite/<version>/libsqlite3.dylib
db.ts

.fileControl(cmd: number, value: any)

要使用高级 sqlite3_file_control API,在你的 Database 实例上调用 .fileControl(cmd, value)。参见 WAL 附属文件清理 获取实际示例。
db.ts
value 可以是:
  • number
  • TypedArray
  • undefinednull

参考

类型参考

数据类型