Skip to main content
查询以标签模板字面量形式编写,客户端支持连接池、事务和预编译语句。
db.ts

特性

  • 标签模板字面量可防止 SQL 注入
  • 事务
  • 命名参数和位置参数
  • 连接池
  • BigInt 支持
  • SASL(SCRAM-SHA-256)、MD5 和明文认证
  • 连接超时
  • 返回数据对象、数组的数组或 Buffer 格式的行
  • 二进制协议支持使其速度更快
  • TLS 支持(和认证模式)
  • 使用环境变量自动配置

数据库支持

Bun.SQL 为多种数据库系统提供统一的 API:

PostgreSQL

PostgreSQL 在以下情况下使用:
  • 连接字符串不匹配 SQLite 或 MySQL 模式(它是回退适配器)
  • 连接字符串显式使用 postgres://postgresql:// 协议
  • 未提供连接字符串且环境变量指向 PostgreSQL
db.ts

MySQL

MySQL 支持内置于 Bun.SQL 中,使用相同的标签模板字面量接口,兼容 MySQL 5.7+ 和 MySQL 8.0+:
db.ts
MySQL 接受多种 URL 格式的连接字符串:
MySQL 数据库支持:
  • 预编译语句:为参数化查询自动创建,并带有语句缓存
  • 二进制协议:用于更好的预编译语句性能和精确的类型处理
  • 多结果集:支持返回多个结果集的存储过程
  • 认证插件:支持 mysql_native_password、caching_sha2_password(MySQL 8.0 默认)和 sha256_password
  • SSL/TLS 连接:可配置的 SSL 模式,类似 PostgreSQL
  • 连接属性:发送到服务器的客户端信息,用于监控
  • 查询流水线:无需等待响应即可执行多个预编译语句

SQLite

SQLite 支持内置于 Bun.SQL 中,使用相同的标签模板字面量接口:
SQLite 接受多种 URL 格式的连接字符串:
不带协议的文件名(如 "myapp.db")需要显式指定 { adapter: "sqlite" },以避免与 PostgreSQL 产生歧义。
SQLite 数据库支持额外的配置选项:
URL 中的查询参数会被解析以设置这些选项:
  • ?mode=roreadonly: true
  • ?mode=rwreadonly: false, create: false
  • ?mode=rwcreadonly: false, create: true(默认)

插入数据

直接将 JavaScript 值传递给 SQL 模板字面量;Bun 负责转义。

批量插入

你也可以传递一个对象数组,Bun 会将其扩展为 INSERT INTO ... VALUES ... 语句。

选择要插入的列

使用 sql(object, ...string) 选择要插入的列。每个列必须在对象上定义。

查询结果

默认情况下,Bun 的 SQL 客户端以对象数组形式返回查询结果,每个对象代表一行,列名作为键。还有两种其他格式可用。

sql``.values() 格式

sql``.values() 方法将每一行作为值数组返回,顺序与查询中的列相同。
结果看起来像:
当查询返回重复的列名时,sql``.values() 非常有用。使用对象(默认)时,因为列名是键,所以最后一个列会胜出。使用 sql``.values() 时,每个列都出现在数组中,因此你可以按索引读取重复列。

sql``.raw() 格式

.raw() 方法将行作为 Buffer 对象的数组返回。用于二进制数据或性能优化。

SQL 片段

Bun 可以根据运行时条件动态构建查询,而不会有 SQL 注入风险。

动态表名

要动态引用表或模式,使用 sql() 助手进行转义:

条件查询

使用 sql() 助手构建带条件子句的查询:

更新中的动态列

使用 sql(object, ...string) 选择要更新的列。每个列必须在对象上定义。如果不列出任何列,则使用对象上的所有键。

动态值和 where in

值列表也可以动态创建,用于 WHERE IN 查询。你也可以传递一个对象数组并指定键,以从中构建列表。

sql.array 助手

sql.array 助手从 JavaScript 数组创建 PostgreSQL 数组字面量:
sql.array 仅适用于 PostgreSQL。多维数组和 NULL 元素可能尚不支持。

sql``.simple()

PostgreSQL 有线协议支持两种类型的查询:“simple”和”extended”。Simple 查询可以包含多个语句但不支持参数,而 extended 查询(默认)支持参数但只允许一个语句。 要在单个查询中运行多个语句,使用 sql``.simple()
Simple 查询适用于数据库迁移和设置脚本。 Simple 查询不能使用参数(${value})。如果你需要参数,请将查询拆分为单独的语句。

文件中的查询

sql.file 从文件读取查询并执行。如果文件使用 $1$2 等占位符,你可以向查询传递参数。不带参数时,文件可以包含多个命令。

不安全查询

sql.unsafe 执行原始 SQL 字符串。谨慎使用:它不会转义用户输入。不带参数时,字符串可以包含多个命令。

执行和取消查询

查询是惰性的:它们只有在被 await 或使用 .execute() 运行时才会开始执行。 要取消正在运行的查询,在查询对象上调用 cancel()

数据库环境变量

你可以使用环境变量配置 sql 连接参数。客户端按优先级顺序检查它们,并从连接字符串格式检测数据库类型。

自动数据库检测

当你使用无参数的 Bun.sql() 或带连接字符串的 new SQL() 时,Bun 会从 URL 格式检测适配器:

MySQL 自动检测

MySQL 在连接字符串匹配以下模式时被选择:
  • mysql://... - MySQL 协议 URL
  • mysql2://... - MySQL2 协议 URL(兼容别名)

SQLite 自动检测

SQLite 在连接字符串匹配以下模式时被选择:
  • :memory: - 内存数据库
  • sqlite://... - SQLite 协议 URL
  • sqlite:... - 不带斜杠的 SQLite 协议
  • file://... - 文件协议 URL
  • file:... - 不带斜杠的文件协议

PostgreSQL 自动检测

PostgreSQL 是不匹配 MySQL 或 SQLite 模式的连接字符串的默认值:

MySQL 环境变量

MySQL 连接可以使用环境变量配置:
如果未提供连接 URL,Bun 会检查这些单独的参数:

PostgreSQL 环境变量

这些环境变量定义 PostgreSQL 连接: 如果未提供连接 URL,Bun 会检查这些单独的参数:

SQLite 环境变量

SQLite 连接可以使用 DATABASE_URL 配置,当其包含 SQLite 兼容的 URL 时:
注意: PostgreSQL 特定的环境变量(如 POSTGRES_URLPGHOST)在使用 SQLite 时会被忽略。

运行时预连接

Bun 可以在启动时预连接到 PostgreSQL,在你的应用程序代码运行之前,这样第一个查询就不需要承受连接延迟。
--sql-preconnect 标志在启动时使用你配置的环境变量建立 PostgreSQL 连接。如果连接失败,错误会被处理而不会导致应用程序崩溃。

连接选项

你可以通过向 SQL 构造函数传递选项来手动配置连接。选项因适配器而异:

MySQL 选项

PostgreSQL 选项

SQLite 选项

  • 连接池:SQLite 不使用连接池,因为它是一个基于文件的数据库。每个 SQL 实例代表一个单一连接。
  • 事务:SQLite 通过保存点支持嵌套事务,类似于 PostgreSQL。
  • 并发访问:SQLite 通过文件锁定处理并发访问。使用 WAL 模式以获得更好的并发性。
  • 内存数据库:使用 :memory: 会创建一个临时数据库,其生命周期仅与连接相同。

动态密码

对于备选认证方案(如访问令牌)或具有轮换密码的数据库,将 password 设置为同步或异步函数。Bun 在连接时调用它以解析密码。

SQLite 特有功能

查询执行

SQLite 同步执行查询,与使用异步 I/O 的 PostgreSQL 不同。API 仍然返回 Promise:

SQLite 编译指令

使用 PRAGMA 语句配置 SQLite 行为:

数据类型差异

SQLite 的类型系统比 PostgreSQL 更灵活:

事务

要启动新事务,使用 sql.begin。此方法同时适用于 PostgreSQL 和 SQLite。对于 PostgreSQL,它会从池中保留一个专用连接。对于 SQLite,它会在单个连接上开始一个事务。 BEGIN 命令会自动发送,包括你指定的任何可选配置。如果在事务期间发生错误,Bun 会发出 ROLLBACK

基本事务

要流水线执行事务中的查询,从回调中返回查询数组:

保存点

保存点会在事务内创建中间检查点,这样部分事务可以回滚而不需要中止整个事务。

分布式事务

两阶段提交 (2PC) 是一种分布式事务协议:阶段 1 中协调器准备每个节点,确保其数据已写入并准备好提交;阶段 2 中节点根据协调器的决定提交或回滚。 在 PostgreSQL 和 MySQL 中,分布式事务会持续存在,超出其原始会话的生命周期,因此特权用户或协调器可以在以后提交或回滚它们。PostgreSQL 将其实现为预备事务;MySQL 使用 XA 事务。 分布式事务期间未捕获的异常会回滚所有更改。否则,你可以在之后提交或回滚事务。

认证

Bun 支持 SCRAM-SHA-256 (SASL)、MD5 和明文认证。SASL 推荐用于更好的安全性。参见 Postgres SASL Authentication

SSL 模式概述

PostgreSQL 的 SSL/TLS 模式控制是否需要安全连接以及执行多少证书验证。

使用连接字符串

你也可以在连接字符串中设置 SSL 模式:

连接池

Bun 的 SQL 客户端管理一个连接池:数据库连接在查询之间被重用,而不是为每个查询打开和关闭,并且池限制了并发连接的数量。
在执行查询之前不会建立连接。

保留连接

sql.reserve() 从池中取出一个连接,并返回一个包装它的客户端,这样你可以在隔离的连接上运行查询。

预编译语句

默认情况下,Bun 的 SQL 客户端为其可以推断为静态的查询创建命名预编译语句,这样速度更快。要禁用它,在连接选项中设置 prepare: false
prepare: false 设置时: 查询仍然使用”extended”协议,但作为未命名预编译语句运行。未命名的预编译语句只存活到下一个指定未命名语句作为目标的 Parse 语句之前。
  • 参数绑定仍然对 SQL 注入是安全的
  • 每个查询由服务器从头解析和计划
  • 查询不会被流水线处理
你可能希望在以下情况下使用 prepare: false
  • 在事务模式下使用 PGBouncer(不过自 PGBouncer 1.21.0 起,协议级别的命名预编译语句在正确配置时得到支持)
  • 调试查询执行计划
  • 处理需要频繁重新生成查询计划的动态 SQL
  • 每个查询只支持一个命令(除非你使用 sql``.simple()
禁用预编译语句可能会减慢频繁使用不同参数运行的查询,因为服务器会从头解析和计划每个查询。

错误处理

客户端为不同的失败场景提供类型化错误。错误是数据库特定的,并扩展了基错误类:

错误类

PostgreSQL 连接错误

认证错误

查询错误

数据类型错误

协议错误

事务错误

SQLite 特定错误

SQLite 错误携带 SQLite 的标准错误码和号:
错误处理示例:

数字和 BigInt

超出 53 位整数范围的数字会作为字符串返回:

使用 BigInt 替代字符串

要将大数字作为 BigInt 而不是字符串获取,在创建 SQL 客户端时将 bigint 选项设置为 true

路线图

我们尚未完成的事项:
  • 使用 --db-preconnect Bun CLI 标志进行连接预加载
  • 列名转换(例如,snake_casecamelCase)。这主要受限于在 C++ 中使用 WebKit 的 WTF::String 实现大小写转换的 Unicode 感知实现。
  • 列类型转换

数据库特有功能

认证方法

MySQL 支持多种认证插件,会自动协商:
  • mysql_native_password - 传统 MySQL 认证,广泛兼容
  • caching_sha2_password - MySQL 8.0+ 默认,使用 RSA 密钥交换更安全
  • sha256_password - 基于 SHA-256 的认证
客户端会自动处理服务器请求时的认证插件切换,包括在非 SSL 连接上进行安全的密码交换。

预编译语句与性能

MySQL 对所有参数化查询使用服务器端预编译语句:

多结果集

MySQL 可以从多语句查询返回多个结果集:

字符集与排序规则

Bun.SQL 对 MySQL 连接使用 utf8mb4 字符集,覆盖所有 Unicode,包括 emoji。

连接属性

Bun 发送客户端信息到 MySQL 用于监控:

类型处理

MySQL 类型被转换为 JavaScript 类型: DATETIMETIMESTAMP 值在线上没有时区,因此 Bun 将其读取为 UTC——你获得的 Date 具有与存储时相同的 UTC 挂钟时间,无论机器的时区如何。这与值的写入方式匹配(绑定的 Date 存储其 UTC 组件)。这也适用于 PostgreSQL 的 timestamp(不带时区);timestamptz 带有显式偏移,不受影响。

与 PostgreSQL 的差异

API 是统一的,但行为有所不同:
  1. 参数占位符:MySQL 内部使用 ?,但 Bun 会自动转换 $1, $2 风格
  2. RETURNING 子句:MySQL 不支持 RETURNING;使用 result.lastInsertRowid 或单独的 SELECT
  3. 数组类型:MySQL 没有像 PostgreSQL 那样的原生数组类型

MySQL 特有功能

我们尚未实现 LOAD DATA INFILE 支持。

PostgreSQL 特有功能

我们尚未实现:
  • COPY 支持
  • LISTEN 支持
  • NOTIFY 支持
我们也没有实现一些较不常见的功能,如:
  • GSSAPI 认证
  • SCRAM-SHA-256-PLUS 支持
  • Point 和 PostGIS 类型
  • 所有多维整数数组类型(仅支持少数几种类型)

常见模式与最佳实践

处理 MySQL 结果集

MySQL 错误处理

MySQL 性能建议

  1. 使用连接池:根据工作负载设置适当的 max 池大小
  2. 启用预编译语句:默认启用,可以提升性能
  3. 为批量操作使用事务:在事务中组合相关查询
  4. 正确使用索引:MySQL 严重依赖索引来提升查询性能
  5. 使用 utf8mb4 字符集:默认设置,处理所有 Unicode 字符

常见问题

计划是添加更多数据库驱动程序。现在统一的 API 支持 PostgreSQL、MySQL 和 SQLite。
适配器会自动从连接字符串检测:
  • mysql://mysql2:// 开头的 URL 使用 MySQL
  • 匹配 SQLite 模式(:memory:sqlite://file://)的 URL 使用 SQLite
  • 其他所有内容默认为 PostgreSQL
是的,支持存储过程,包括 OUT 参数和多结果集:
是的,你可以使用任何 MySQL 特有的语法:

为什么不直接使用现有库?

你也可以在 Bun 中使用 npm 包,如 postgres.js、pg 和 node-postgres。它们都是很好的选择。 有两个原因:
  1. 我们认为在 Bun 中内置数据库驱动对开发者来说更简单。你花在挑选库上的时间,本可以用来构建你的应用。
  2. 我们使用一些 JavaScriptCore 引擎内部机制来更快地创建对象,这在库中很难实现。

致谢

衷心感谢 @porsagerpostgres.js 为 API 接口提供了灵感。