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 连接字符串格式
MySQL 连接字符串格式
MySQL 接受多种 URL 格式的连接字符串:
MySQL 特有功能
MySQL 特有功能
MySQL 数据库支持:
- 预编译语句:为参数化查询自动创建,并带有语句缓存
- 二进制协议:用于更好的预编译语句性能和精确的类型处理
- 多结果集:支持返回多个结果集的存储过程
- 认证插件:支持 mysql_native_password、caching_sha2_password(MySQL 8.0 默认)和 sha256_password
- SSL/TLS 连接:可配置的 SSL 模式,类似 PostgreSQL
- 连接属性:发送到服务器的客户端信息,用于监控
- 查询流水线:无需等待响应即可执行多个预编译语句
SQLite
SQLite 支持内置于Bun.SQL 中,使用相同的标签模板字面量接口:
SQLite 连接字符串格式
SQLite 连接字符串格式
SQLite 接受多种 URL 格式的连接字符串:
不带协议的文件名(如
"myapp.db")需要显式指定 { adapter: "sqlite" },以避免与 PostgreSQL 产生歧义。SQLite 特有选项
SQLite 特有选项
SQLite 数据库支持额外的配置选项:URL 中的查询参数会被解析以设置这些选项:
?mode=ro→readonly: true?mode=rw→readonly: false, create: false?mode=rwc→readonly: 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():
${value})。如果你需要参数,请将查询拆分为单独的语句。
文件中的查询
sql.file 从文件读取查询并执行。如果文件使用 $1 和 $2 等占位符,你可以向查询传递参数。不带参数时,文件可以包含多个命令。
不安全查询
sql.unsafe 执行原始 SQL 字符串。谨慎使用:它不会转义用户输入。不带参数时,字符串可以包含多个命令。
执行和取消查询
查询是惰性的:它们只有在被 await 或使用.execute() 运行时才会开始执行。
要取消正在运行的查询,在查询对象上调用 cancel()。
数据库环境变量
你可以使用环境变量配置sql 连接参数。客户端按优先级顺序检查它们,并从连接字符串格式检测数据库类型。
自动数据库检测
当你使用无参数的Bun.sql() 或带连接字符串的 new SQL() 时,Bun 会从 URL 格式检测适配器:
MySQL 自动检测
MySQL 在连接字符串匹配以下模式时被选择:mysql://...- MySQL 协议 URLmysql2://...- MySQL2 协议 URL(兼容别名)
SQLite 自动检测
SQLite 在连接字符串匹配以下模式时被选择::memory:- 内存数据库sqlite://...- SQLite 协议 URLsqlite:...- 不带斜杠的 SQLite 协议file://...- 文件协议 URLfile:...- 不带斜杠的文件协议
PostgreSQL 自动检测
PostgreSQL 是不匹配 MySQL 或 SQLite 模式的连接字符串的默认值:MySQL 环境变量
MySQL 连接可以使用环境变量配置:PostgreSQL 环境变量
这些环境变量定义 PostgreSQL 连接:
如果未提供连接 URL,Bun 会检查这些单独的参数:
SQLite 环境变量
SQLite 连接可以使用DATABASE_URL 配置,当其包含 SQLite 兼容的 URL 时:
POSTGRES_URL 和 PGHOST)在使用 SQLite 时会被忽略。
运行时预连接
Bun 可以在启动时预连接到 PostgreSQL,在你的应用程序代码运行之前,这样第一个查询就不需要承受连接延迟。--sql-preconnect 标志在启动时使用你配置的环境变量建立 PostgreSQL 连接。如果连接失败,错误会被处理而不会导致应用程序崩溃。
连接选项
你可以通过向SQL 构造函数传递选项来手动配置连接。选项因适配器而异:
MySQL 选项
PostgreSQL 选项
SQLite 选项
SQLite 连接说明
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())
错误处理
客户端为不同的失败场景提供类型化错误。错误是数据库特定的,并扩展了基错误类:错误类
SQLite 特定错误
SQLite 错误携带 SQLite 的标准错误码和号:常见 SQLite 错误码
常见 SQLite 错误码
错误处理示例:
数字和 BigInt
超出 53 位整数范围的数字会作为字符串返回:使用 BigInt 替代字符串
要将大数字作为BigInt 而不是字符串获取,在创建 SQL 客户端时将 bigint 选项设置为 true:
路线图
我们尚未完成的事项:- 使用
--db-preconnectBun CLI 标志进行连接预加载 - 列名转换(例如,
snake_case到camelCase)。这主要受限于在 C++ 中使用 WebKit 的WTF::String实现大小写转换的 Unicode 感知实现。 - 列类型转换
数据库特有功能
认证方法
MySQL 支持多种认证插件,会自动协商:mysql_native_password- 传统 MySQL 认证,广泛兼容caching_sha2_password- MySQL 8.0+ 默认,使用 RSA 密钥交换更安全sha256_password- 基于 SHA-256 的认证
预编译语句与性能
MySQL 对所有参数化查询使用服务器端预编译语句:多结果集
MySQL 可以从多语句查询返回多个结果集:字符集与排序规则
Bun.SQL 对 MySQL 连接使用 utf8mb4 字符集,覆盖所有 Unicode,包括 emoji。
连接属性
Bun 发送客户端信息到 MySQL 用于监控:类型处理
MySQL 类型被转换为 JavaScript 类型:DATETIME 和 TIMESTAMP 值在线上没有时区,因此 Bun 将其读取为 UTC——你获得的 Date 具有与存储时相同的 UTC 挂钟时间,无论机器的时区如何。这与值的写入方式匹配(绑定的 Date 存储其 UTC 组件)。这也适用于 PostgreSQL 的 timestamp(不带时区);timestamptz 带有显式偏移,不受影响。
与 PostgreSQL 的差异
API 是统一的,但行为有所不同:- 参数占位符:MySQL 内部使用
?,但 Bun 会自动转换$1, $2风格 - RETURNING 子句:MySQL 不支持 RETURNING;使用
result.lastInsertRowid或单独的 SELECT - 数组类型:MySQL 没有像 PostgreSQL 那样的原生数组类型
MySQL 特有功能
我们尚未实现LOAD DATA INFILE 支持。
PostgreSQL 特有功能
我们尚未实现:COPY支持LISTEN支持NOTIFY支持
- GSSAPI 认证
SCRAM-SHA-256-PLUS支持- Point 和 PostGIS 类型
- 所有多维整数数组类型(仅支持少数几种类型)
常见模式与最佳实践
处理 MySQL 结果集
MySQL 错误处理
MySQL 性能建议
- 使用连接池:根据工作负载设置适当的
max池大小 - 启用预编译语句:默认启用,可以提升性能
- 为批量操作使用事务:在事务中组合相关查询
- 正确使用索引:MySQL 严重依赖索引来提升查询性能
- 使用
utf8mb4字符集:默认设置,处理所有 Unicode 字符
常见问题
为什么是 `Bun.sql` 而不是 `Bun.postgres`?
为什么是 `Bun.sql` 而不是 `Bun.postgres`?
计划是添加更多数据库驱动程序。现在统一的 API 支持 PostgreSQL、MySQL 和 SQLite。
如何知道正在使用哪个数据库适配器?
如何知道正在使用哪个数据库适配器?
适配器会自动从连接字符串检测:
- 以
mysql://或mysql2://开头的 URL 使用 MySQL - 匹配 SQLite 模式(
:memory:、sqlite://、file://)的 URL 使用 SQLite - 其他所有内容默认为 PostgreSQL
MySQL 存储过程是否受支持?
MySQL 存储过程是否受支持?
是的,支持存储过程,包括 OUT 参数和多结果集:
可以使用 MySQL 特有的 SQL 语法吗?
可以使用 MySQL 特有的 SQL 语法吗?
是的,你可以使用任何 MySQL 特有的语法:
为什么不直接使用现有库?
你也可以在 Bun 中使用 npm 包,如 postgres.js、pg 和 node-postgres。它们都是很好的选择。 有两个原因:- 我们认为在 Bun 中内置数据库驱动对开发者来说更简单。你花在挑选库上的时间,本可以用来构建你的应用。
- 我们使用一些 JavaScriptCore 引擎内部机制来更快地创建对象,这在库中很难实现。