> ## Documentation Index
> Fetch the complete documentation index at: https://bun.zhcndoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SQL

> Bun 提供原生绑定，通过统一的基于 Promise 的 API 来操作 SQL 数据库，支持 PostgreSQL、MySQL 和 SQLite。

该接口旨在具备高性能，使用带标签的模板字面量来构建查询，并提供诸如连接池、事务和预处理语句等功能。

```ts title="db.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { sql, SQL } from "bun";

// PostgreSQL（默认）
const users = await sql`
  SELECT * FROM users
  WHERE active = ${true}
  LIMIT ${10}
`;

// 使用 MySQL
const mysql = new SQL("mysql://user:pass@localhost:3306/mydb");
const mysqlResults = await mysql`
  SELECT * FROM users 
  WHERE active = ${true}
`;

// 使用 SQLite
const sqlite = new SQL("sqlite://myapp.db");
const sqliteResults = await sqlite`
  SELECT * FROM users 
  WHERE active = ${1}
`;
```

### 功能特性

* 使用标签模板字面量防止 SQL 注入
* 事务支持
* 命名和位置参数
* 连接池
* 支持 `BigInt`
* 支持 SASL 认证（SCRAM-SHA-256）、MD5 和明文认证
* 连接超时设置
* 查询结果可作为数据对象、数组的数组或 Buffer 返回
* 支持二进制协议，性能更高
* TLS 支持（和认证模式）
* 环境变量自动配置

***

## 数据库支持

`Bun.SQL` 提供多数据库系统的统一 API：

### PostgreSQL

PostgreSQL 适用于以下情况：

* 连接字符串不符合 SQLite 或 MySQL 格式（作为默认适配器）
* 明确使用 `postgres://` 或 `postgresql://` 协议的连接字符串
* 无连接字符串，但环境变量指向 PostgreSQL

```ts title="db.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { sql } from "bun";
// 当未设置 DATABASE_URL 或为 PostgreSQL URL 时使用 PostgreSQL
await sql`SELECT ...`;

import { SQL } from "bun";
const pg = new SQL("postgres://user:pass@localhost:5432/mydb");
await pg`SELECT ...`;
```

### MySQL

Bun.SQL 内置 MySQL 支持，使用相同的标签模板字面量接口，兼容 MySQL 5.7+ 和 MySQL 8.0+：

```ts title="db.ts" icon="https://mintcdn.com/bun-zhcndoc/cnUTwgMuf4cCrwC-/icons/typescript.svg?fit=max&auto=format&n=cnUTwgMuf4cCrwC-&q=85&s=e7767043c9e885c34f2d6c8fe2a95217" theme={"theme":{"light":"github-light","dark":"dracula"}}
import { SQL } from "bun";

// MySQL 连接
const mysql = new SQL("mysql://user:password@localhost:3306/database");
const mysql2 = new SQL("mysql2://user:password@localhost:3306/database"); // mysql2 协议同样支持

// 使用选项对象
const mysql3 = new SQL({
  adapter: "mysql",
  hostname: "localhost",
  port: 3306,
  database: "myapp",
  username: "dbuser",
  password: "secretpass",
});

// 支持参数 — 会自动使用预处理语句
const users = await mysql`SELECT * FROM users WHERE id = ${userId}`;

// 事务和 PostgreSQL 使用方法相同
await mysql.begin(async tx => {
  await tx`INSERT INTO users (name) VALUES (${"Alice"})`;
  await tx`UPDATE accounts SET balance = balance - 100 WHERE user_id = ${userId}`;
});

// 批量插入
const newUsers = [
  { name: "Alice", email: "alice@example.com" },
  { name: "Bob", email: "bob@example.com" },
];
await mysql`INSERT INTO users ${mysql(newUsers)}`;
```

<Accordion title="MySQL 连接字符串格式">
  MySQL 支持多种 URL 格式作为连接字符串：

  ```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
  // 标准 mysql:// 协议
  new SQL("mysql://user:pass@localhost:3306/database");
  new SQL("mysql://user:pass@localhost/database"); // 默认端口 3306

  // mysql2:// 协议（兼容 mysql2 npm 包）
  new SQL("mysql2://user:pass@localhost:3306/database");

  // 含查询参数
  new SQL("mysql://user:pass@localhost/db?ssl=true");

  // Unix 套接字连接
  new SQL("mysql://user:pass@/database?socket=/var/run/mysqld/mysqld.sock");
  ```
</Accordion>

<Accordion title="MySQL 特有功能">
  MySQL 数据库支持：

  * **预处理语句**：参数化查询自动创建且缓存语句
  * **二进制协议**：提升预处理语句性能并支持准确类型处理
  * **多结果集**：支持存储过程返回多个结果集
  * **认证插件**：支持 mysql\_native\_password、caching\_sha2\_password（MySQL 8.0 默认）和 sha256\_password
  * **SSL/TLS 连接**：SSL 模式配置类似 PostgreSQL
  * **连接属性**：客户端信息发送到服务器便于监控
  * **查询流水线**：无需等待响应即可执行多个预处理语句
</Accordion>

### SQLite

Bun.SQL 内置 SQLite 支持，使用相同标签模板字面量接口：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { SQL } from "bun";

// 内存数据库
const memory = new SQL(":memory:");
const memory2 = new SQL("sqlite://:memory:");

// 文件数据库
const sql1 = new SQL("sqlite://myapp.db");

// 使用选项对象
const sql2 = new SQL({
  adapter: "sqlite",
  filename: "./data/app.db",
});

// 简单文件名必须明确告知适配器
const sql3 = new SQL("myapp.db", { adapter: "sqlite" });
```

<Accordion title="SQLite 连接字符串格式">
  SQLite 支持多种 URL 格式作为连接字符串：

  ```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
  // 标准 sqlite:// 协议
  new SQL("sqlite://path/to/database.db");
  new SQL("sqlite:path/to/database.db"); // 无斜杠

  // file:// 协议（也视为 SQLite）
  new SQL("file://path/to/database.db");
  new SQL("file:path/to/database.db");

  // 特殊内存数据库
  new SQL(":memory:");
  new SQL("sqlite://:memory:");
  new SQL("file://:memory:");

  // 相对和绝对路径
  new SQL("sqlite://./local.db"); // 相对于当前目录
  new SQL("sqlite://../parent/db.db"); // 上级目录
  new SQL("sqlite:///absolute/path.db"); // 绝对路径

  // 带参数
  new SQL("sqlite://data.db?mode=ro"); // 只读
  new SQL("sqlite://data.db?mode=rw"); // 读写无创建
  new SQL("sqlite://data.db?mode=rwc"); // 读写并允许创建（默认）
  ```

  <Note>
    简单文件名（如 `"myapp.db"`）必须显式设置 `{ adapter: "sqlite" }`，以避免和 PostgreSQL 混淆。
  </Note>
</Accordion>

<Accordion title="SQLite 特定选项">
  SQLite 支持额外配置选项：

  ```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
  const sql = new SQL({
    adapter: "sqlite",
    filename: "app.db",

    // SQLite 特定选项
    readonly: false, // 只读打开
    create: true, // 不存在则创建数据库
    readwrite: true, // 读写访问

    // 额外 Bun:sqlite 选项
    strict: true, // 开启严格模式
    safeIntegers: false, // 使用 JS 数字处理整数
  });
  ```

  URL 中的查询参数会映射到这些配置：

  * `?mode=ro` → `readonly: true`
  * `?mode=rw` → `readonly: false, create: false`
  * `?mode=rwc` → `readonly: false, create: true`（默认）
</Accordion>

## 插入数据

你可以直接将 JavaScript 值传入 SQL 模板字面量，框架会自动帮你转义。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { sql } from "bun";

// 基础插入，直接传值
const [user] = await sql`
  INSERT INTO users (name, email) 
  VALUES (${name}, ${email})
  RETURNING *
`;

// 使用对象辅助，语法更简洁
const userData = {
  name: "Alice",
  email: "alice@example.com",
};

const [newUser] = await sql`
  INSERT INTO users ${sql(userData)}
  RETURNING *
`;
// 展开为：INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')
```

### 批量插入

你也可以传入对象数组，自动展开成 `INSERT INTO ... VALUES ...` 语句：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const users = [
  { name: "Alice", email: "alice@example.com" },
  { name: "Bob", email: "bob@example.com" },
  { name: "Charlie", email: "charlie@example.com" },
];

await sql`INSERT INTO users ${sql(users)}`;
```

### 选择插入列

可通过 `sql(object, ...string)` 指定插入哪些列，指定的列必须都在对象中：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const user = {
  name: "Alice",
  email: "alice@example.com",
  age: 25,
};

await sql`INSERT INTO users ${sql(user, "name", "email")}`;
// 仅插入 name 和 email 列，其余字段忽略
```

***

## 查询结果

默认情况下，Bun 的 SQL 客户端会返回以列名为键的对象数组，每个对象代表一行。若需要不同格式，客户端还支持另外两种方法返回结果。

### `sql``.values()` 格式

`.values()` 返回二维数组，每行是值数组，顺序与查询列相同：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const rows = await sql`SELECT * FROM users`.values();
console.log(rows);
```

结果类似：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
[
  ["Alice", "alice@example.com"],
  ["Bob", "bob@example.com"],
];
```

当查询中存在重复列名时，使用 `.values()` 特别有用；对象格式会覆盖前面同名列，而 `.values()` 会保留所有列，可通过下标访问。

### `sql``.raw()` 格式

`.raw()` 返回 Buffer 类型数据的二维数组，适用于处理二进制数据或追求性能场景：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const rows = await sql`SELECT * FROM users`.raw();
console.log(rows); // [[Buffer, Buffer], [Buffer, Buffer], [Buffer, Buffer]]
```

***

## SQL 片段

数据库应用常需要根据运行时条件动态构建查询，Bun 提供安全构造方法防止 SQL 注入。

### 动态表名

需要动态引用表或模式名时，使用 `sql()` 辅助以正确转义：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 安全动态引用表名
await sql`SELECT * FROM ${sql("users")}`;

// 带模式限定
await sql`SELECT * FROM ${sql("public.users")}`;
```

### 条件查询

使用 `sql()` 动态构造条件子句，实现灵活查询：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 可选 WHERE 子句
const filterAge = true;
const minAge = 21;
const ageFilter = sql`AND age > ${minAge}`;
await sql`
  SELECT * FROM users
  WHERE active = ${true}
  ${filterAge ? ageFilter : sql``}
`;
```

### 更新时动态列

`sql(object, ...string)` 可指定更新哪些列，指定的列必须在对象内。若不指定列，将使用对象所有键更新：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
await sql`UPDATE users SET ${sql(user, "name", "email")} WHERE id = ${user.id}`;
// 使用对象所有键更新
await sql`UPDATE users SET ${sql(user)} WHERE id = ${user.id}`;
```

### 动态值和 `WHERE IN`

值列表也可动态创建，方便构造 `WHERE IN` 查询。也可传对象数组并指定键名：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
await sql`SELECT * FROM users WHERE id IN ${sql([1, 2, 3])}`;

const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
];
await sql`SELECT * FROM users WHERE id IN ${sql(users, "id")}`;
```

### `sql.array` 辅助

`sql.array` 用于将 JS 数组转换为 PostgreSQL 数组字面量：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// PostgreSQL 数组字面量
await sql`INSERT INTO tags (items) VALUES (${sql.array(["red", "blue", "green"])})`;
// 生成：INSERT INTO tags (items) VALUES (ARRAY['red', 'blue', 'green'])

// 也适用于数值数组
await sql`SELECT * FROM products WHERE ids = ANY(${sql.array([1, 2, 3])})`;
// 生成：SELECT * FROM products WHERE ids = ANY(ARRAY[1, 2, 3])
```

<Note>`sql.array` 仅支持 PostgreSQL，多维数组和 NULL 元素可能暂不支持。</Note>

***

## `sql``.simple()`

PostgreSQL 协议支持两类查询：“简单”和“扩展”查询。简单查询支持多条语句但不支持参数，扩展查询支持参数但只能一条语句。

要在一次查询中执行多条语句，使用 `sql``.simple()`：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 一次执行多条语句
await sql`
  SELECT 1;
  SELECT 2;
`.simple();
```

简单查询常用于数据库迁移和初始化脚本。

注意，简单查询不支持参数（`${value}`），如需参数，必须拆分查询语句。

### 文件查询

可以用 `sql.file` 读取文件执行查询，文件中如果含有 $1、$2 等参数，可传入参数数组。若无参数，文件可包含多条命令：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const result = await sql.file("query.sql", [1, 2, 3]);
```

### 不安全查询

用 `sql.unsafe` 执行原始 SQL 字符串。此方法不做转义，须谨慎使用。无参数时允许多条命令执行。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 多条命令无参数
const result = await sql.unsafe(`
  SELECT ${userColumns} FROM users;
  SELECT ${accountColumns} FROM accounts;
`);

// 带参数（只支持单条命令）
const result = await sql.unsafe("SELECT " + dangerous + " FROM users WHERE id = $1", [id]);
```

### 执行和取消查询

Bun 的 SQL 操作是惰性的，仅在调用 `await` 或 `.execute()` 时报真正执行。
你可以调用查询对象的 `cancel()` 方法取消当前执行的查询：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const query = sql`SELECT * FROM users`.execute();
setTimeout(() => query.cancel(), 100);
await query;
```

***

## 数据库环境变量

`sql` 连接参数可通过环境变量配置，客户端按优先级检测变量并根据连接字符串格式自动识别数据库类型。

### 自动数据库检测

使用 `Bun.sql()` 无参或 `new SQL()` 传连接字符串时，适配器自动根据 URL 格式检测：

#### MySQL 自动检测

连接字符串匹配以下格式时自动使用 MySQL：

* `mysql://...` — MySQL 协议
* `mysql2://...` — MySQL2 协议（兼容别名）

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 以下均自动使用 MySQL（无需指定适配器）
const sql1 = new SQL("mysql://user:pass@localhost/mydb");
const sql2 = new SQL("mysql2://user:pass@localhost:3306/mydb");

// 也支持通过环境变量 DATABASE_URL
DATABASE_URL="mysql://user:pass@localhost/mydb" bun run app.js
DATABASE_URL="mysql2://user:pass@localhost:3306/mydb" bun run app.js
```

#### SQLite 自动检测

连接字符串匹配以下格式时自动使用 SQLite：

* `:memory:` — 内存数据库
* `sqlite://...` — SQLite 协议
* `sqlite:...` — 无斜杠的 SQLite 协议
* `file://...` — 文件协议
* `file:...` — 无斜杠的文件协议

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 以下均自动使用 SQLite
const sql1 = new SQL(":memory:");
const sql2 = new SQL("sqlite://app.db");
const sql3 = new SQL("file://./database.db");

// 也支持环境变量 DATABASE_URL
DATABASE_URL=":memory:" bun run app.js
DATABASE_URL="sqlite://myapp.db" bun run app.js
DATABASE_URL="file://./data/app.db" bun run app.js
```

#### PostgreSQL 自动检测

不匹配 MySQL 或 SQLite 格式时，默认使用 PostgreSQL：

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
# PostgreSQL 检测示例
DATABASE_URL="postgres://user:pass@localhost:5432/mydb" bun run app.js
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb" bun run app.js

# 或者任何其他不匹配 MySQL 和 SQLite 的 URL
DATABASE_URL="localhost:5432/mydb" bun run app.js
```

### MySQL 环境变量

MySQL 连接可通过环境变量配置：

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
# 优先使用的连接 URL
MYSQL_URL="mysql://user:pass@localhost:3306/mydb"

# 兼容 DATABASE_URL 格式（MySQL 协议）
DATABASE_URL="mysql://user:pass@localhost:3306/mydb"
DATABASE_URL="mysql2://user:pass@localhost:3306/mydb"
```

无连接 URL 时，MySQL 支持如下独立参数：

| 环境变量                     | 默认值         | 说明                 |
| ------------------------ | ----------- | ------------------ |
| `MYSQL_HOST`             | `localhost` | 数据库主机              |
| `MYSQL_PORT`             | `3306`      | 端口                 |
| `MYSQL_USER`             | `root`      | 用户名                |
| `MYSQL_PASSWORD`         | 空字符串        | 密码                 |
| `MYSQL_DATABASE`         | `mysql`     | 数据库名               |
| `MYSQL_URL`              | 空字符串        | MySQL 主要连接 URL     |
| `TLS_MYSQL_DATABASE_URL` | 空字符串        | 启用 SSL/TLS 的连接 URL |

### PostgreSQL 环境变量

以下变量可用于定义 PostgreSQL 连接：

| 环境变量                        | 说明                    |
| --------------------------- | --------------------- |
| `POSTGRES_URL`              | PostgreSQL 主要连接 URL   |
| `DATABASE_URL`              | 兼容的另一个连接 URL          |
| `PGURL`                     | 兼容连接 URL              |
| `PG_URL`                    | 兼容连接 URL              |
| `TLS_POSTGRES_DATABASE_URL` | 启用 SSL/TLS 的连接 URL    |
| `TLS_DATABASE_URL`          | 另一个启用 SSL/TLS 的连接 URL |

无 URL 时，检测以下单独参数：

| 环境变量         | 备用变量                         | 默认值         | 说明   |
| ------------ | ---------------------------- | ----------- | ---- |
| `PGHOST`     | -                            | `localhost` | 主机   |
| `PGPORT`     | -                            | `5432`      | 端口   |
| `PGUSERNAME` | `PGUSER`, `USER`, `USERNAME` | `postgres`  | 用户名  |
| `PGPASSWORD` | -                            | 空字符串        | 密码   |
| `PGDATABASE` | -                            | 当前用户名       | 数据库名 |

### SQLite 环境变量

当连接字符串是 SQLite 兼容时，使用 `DATABASE_URL` 配置：

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
# SQLite 连接示例
DATABASE_URL=":memory:"
DATABASE_URL="sqlite://./app.db"
DATABASE_URL="file:///absolute/path/to/db.sqlite"
```

**注意：** 使用 SQLite 时，会忽略 PostgreSQL 专用环境变量（如 `POSTGRES_URL`、`PGHOST` 等）。

***

## 运行时预连接

Bun 可在启动时预先连接 PostgreSQL，减少首次查询的连接延迟，提高性能。

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
# 启用 PostgreSQL 预连接
bun --sql-preconnect index.js

# 配合 DATABASE_URL 环境变量使用
DATABASE_URL=postgres://user:pass@localhost:5432/db bun --sql-preconnect index.js

# 可与其他运行时参数结合
bun --sql-preconnect --hot index.js
```

`--sql-preconnect` 会自动使用环境变量配置建立连接。连接失败不会导致程序崩溃，错误会被安全处理。

***

## 连接选项

可以通过传入参数手动配置数据库连接。选项根据适配器不同而异：

### MySQL 选项

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { SQL } from "bun";

const sql = new SQL({
  // MySQL 必须指定
  adapter: "mysql",

  // 连接配置
  hostname: "localhost",
  port: 3306,
  database: "myapp",
  username: "dbuser",
  password: "secretpass",

  // Unix 套接字连接（替代 hostname/port）
  // socket: "/var/run/mysqld/mysqld.sock",

  // 连接池设置
  max: 20, // 最大连接数（默认10）
  idleTimeout: 30, // 空闲连接 30 秒后关闭
  maxLifetime: 0, // 连接最大存活时间（秒），0 表示无限
  connectionTimeout: 30, // 建立连接超时（秒）

  // SSL/TLS 选项
  ssl: "prefer", // 可设 "disable", "require", "verify-ca", "verify-full"
  // tls: {
  //   rejectUnauthorized: true,
  //   ca: "path/to/ca.pem",
  //   key: "path/to/key.pem",
  //   cert: "path/to/cert.pem",
  // },

  // 回调函数
  onconnect: client => {
    console.log("已连接到 MySQL");
  },
  onclose: (client, err) => {
    if (err) {
      console.error("MySQL 连接错误:", err);
    } else {
      console.log("MySQL 连接关闭");
    }
  },
});
```

### PostgreSQL 选项

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { SQL } from "bun";

const sql = new SQL({
  // 连接配置（适配器自动默认为 PostgreSQL）
  url: "postgres://user:pass@localhost:5432/dbname",

  // 可替代配置
  hostname: "localhost",
  port: 5432,
  database: "myapp",
  username: "dbuser",
  password: "secretpass",

  // 连接池设置
  max: 20, // 最大连接数
  idleTimeout: 30, // 空闲连接 30 秒关闭
  maxLifetime: 0, // 连接最大存活时间，0 表示无限
  connectionTimeout: 30, // 建立连接超时

  // SSL/TLS 选项
  tls: true,
  // tls: {
  //   rejectUnauthorized: true,
  //   requestCert: true,
  //   ca: "path/to/ca.pem",
  //   key: "path/to/key.pem",
  //   cert: "path/to/cert.pem",
  //   checkServerIdentity(hostname, cert) {
  //     ...
  //   },
  // },

  // 回调函数
  onconnect: client => {
    console.log("已连接到 PostgreSQL");
  },
  onclose: client => {
    console.log("PostgreSQL 连接关闭");
  },
});
```

### SQLite 选项

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { SQL } from "bun";

const sql = new SQL({
  // 必须指定适配器
  adapter: "sqlite",
  filename: "./data/app.db", // 或 ":memory:" 表示内存数据库

  // SQLite 文件访问模式
  readonly: false, // 只读打开
  create: true, // 不存在则创建
  readwrite: true, // 支持读写

  // SQLite 数据处理设置
  strict: true, // 开启严格模式提升类型安全
  safeIntegers: false, // 超出 JS 数字范围的整数使用 BigInt

  // 回调函数
  onconnect: client => {
    console.log("SQLite 数据库已打开");
  },
  onclose: client => {
    console.log("SQLite 数据库已关闭");
  },
});
```

<Accordion title="SQLite 连接注意事项">
  * **连接池**：SQLite 是文件型数据库，不使用连接池，每个 `SQL` 实例对应单一连接。
  * **事务**：SQLite 支持通过保存点实现嵌套事务，类似 PostgreSQL。
  * **并发访问**：SQLite 通过文件锁控制并发，建议使用 WAL 日志模式以提升并发能力。
  * **内存数据库**：`:memory:` 创建临时数据库，仅存活于连接生命周期内。
</Accordion>

***

## 动态密码

当客户端需要用访问令牌或轮换密码等动态认证时，可提供同步或异步函数动态获取密码：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { SQL } from "bun";

const sql = new SQL(url, {
  // 其他连接配置
  ...
  // 用于获取数据库用户密码的函数
  password: async () => await signer.getAuthToken(),
});
```

***

## SQLite 特有功能

### 查询执行

SQLite 查询是同步执行的，但 API 依然返回 Promise 保持一致：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const sqlite = new SQL("sqlite://app.db");

// 使用体验和 PostgreSQL 一样，但底层同步执行
const users = await sqlite`SELECT * FROM users`;

// 参数传递方式一致
const user = await sqlite`SELECT * FROM users WHERE id = ${userId}`;
```

### SQLite PRAGMA 语句

可使用 PRAGMA 配置 SQLite 行为：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const sqlite = new SQL("sqlite://app.db");

// 启用外键支持
await sqlite`PRAGMA foreign_keys = ON`;

// 设置 WAL 日志模式提升并发
await sqlite`PRAGMA journal_mode = WAL`;

// 校验数据库完整性
const integrity = await sqlite`PRAGMA integrity_check`;
```

### 数据类型差异

SQLite 类型系统比 PostgreSQL 灵活：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// SQLite 存储 5 种基础类型：NULL、INTEGER、REAL、TEXT 和 BLOB
const sqlite = new SQL("sqlite://app.db");

// SQLite 类型宽松
await sqlite`
  CREATE TABLE flexible (
    id INTEGER PRIMARY KEY,
    data TEXT,        -- 数字能存为字符串
    value NUMERIC,    -- 可以是整数、浮点或文本
    blob BLOB         -- 二进制数据
  )
`;

// JS 值会自动转换
await sqlite`INSERT INTO flexible VALUES (${1}, ${"text"}, ${123.45}, ${Buffer.from("binary")})`;
```

***

## 事务

用 `sql.begin` 启动事务，支持 PostgreSQL 和 SQLite。PostgreSQL 会从连接池中保留连接，SQLite 则在单一连接上开始事务。

开始时自动发送 `BEGIN` 命令，支持传入可选参数。出现错误会自动回退（`ROLLBACK`），保证程序继续执行。

### 基本事务

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
await sql.begin(async tx => {
  // 该函数内所有查询都运行于事务中
  await tx`INSERT INTO users (name) VALUES (${"Alice"})`;
  await tx`UPDATE accounts SET balance = balance - 100 WHERE user_id = 1`;

  // 没有抛错则自动提交
  // 抛错则回滚
});
```

通过返回查询数组，也可以让事务实现流水线执行：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
await sql.begin(async tx => {
  return [
    tx`INSERT INTO users (name) VALUES (${"Alice"})`,
    tx`UPDATE accounts SET balance = balance - 100 WHERE user_id = 1`,
  ];
});
```

### 保存点（Savepoints）

保存点允许在事务中设置检查点，支持部分回滚，不影响整体事务。适合复杂事务。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
await sql.begin(async tx => {
  await tx`INSERT INTO users (name) VALUES (${"Alice"})`;

  await tx.savepoint(async sp => {
    // 此处段落可独立回滚
    await sp`UPDATE users SET status = 'active'`;
    if (someCondition) {
      throw new Error("Rollback to savepoint");
    }
  });

  // 保存点回滚后继续事务
  await tx`INSERT INTO audit_log (action) VALUES ('user_created')`;
});
```

### 分布式事务

两阶段提交（2PC）协议允许协调多个节点，保证跨节点持久化数据一致性和锁管理。

PostgreSQL 和 MySQL 支持分布式事务，可供管理员或协调者后续提交或回滚。

如果分布式事务中有未捕获异常，系统会自动回滚。正常时，可以延迟提交或回滚。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 开始分布式事务
await sql.beginDistributed("tx1", async tx => {
  await tx`INSERT INTO users (name) VALUES (${"Alice"})`;
});

// 后续提交或回滚
await sql.commitDistributed("tx1");
// 或
await sql.rollbackDistributed("tx1");
```

***

## 认证

Bun 支持 SCRAM-SHA-256（SASL）、MD5 和明文认证。推荐使用 SASL 增强安全性。详见 [Postgres SASL 认证](https://www.postgresql.org/docs/current/sasl-authentication.html)。

### SSL 模式概述

PostgreSQL 支持多种 SSL/TLS 模式，决定连接时安全策略和证书验证级别。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const sql = new SQL({
  hostname: "localhost",
  username: "user",
  password: "password",
  ssl: "disable", // 可选 "prefer" | "require" | "verify-ca" | "verify-full"
});
```

| SSL 模式        | 说明                             |
| ------------- | ------------------------------ |
| `disable`     | 不使用 SSL/TLS。如服务端要求 SSL，连接将失败   |
| `prefer`      | 优先使用 SSL，失败则降级为非 SSL。默认模式      |
| `require`     | 必须启用 SSL，但不验证证书。无法建立 SSL 连接则失败 |
| `verify-ca`   | 验证服务器证书由受信任 CA 签发，验证失败则失败      |
| `verify-full` | 最安全模式，验证证书且验证域名匹配，防止恶意证书和中间人攻击 |

### 连接字符串中设置

SSL 模式也可直接在连接字符串中指定：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// prefer 模式
const sql = new SQL("postgres://user:password@localhost/mydb?sslmode=prefer");

// verify-full 模式
const sql = new SQL("postgres://user:password@localhost/mydb?sslmode=verify-full");
```

***

## 连接池

Bun SQL 自动管理连接池，复用连接执行多条查询，减少建立关闭连接开销，且管理并发连接数。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const sql = new SQL({
  max: 20, // 最大连接数 20
  idleTimeout: 30, // 空闲 30 秒关闭连接
  maxLifetime: 3600, // 连接最大存活 1 小时
  connectionTimeout: 10, // 连接超时 10 秒
});
```

在第一次查询时连接池才会启动：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const sql = Bun.SQL(); // 未连接

await sql`...`; // 连接池启动，最多创建 max 连接，复用空闲连接
await sql`...`; // 复用已有连接

// 并行使用多个连接
await Promise.all([
  sql`INSERT INTO users ${sql({ name: "Alice" })}`,
  sql`UPDATE users SET name = ${user.name} WHERE id = ${user.id}`,
]);

await sql.close(); // 等待所有查询完成并关闭连接池
await sql.close({ timeout: 5 }); // 最多等待 5 秒关闭
await sql.close({ timeout: 0 }); // 立即关闭所有连接
```

***

## 保留连接

Bun 允许保留连接池中的单个连接，返回包裹该连接的客户端，用于执行隔离查询。

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 保留独占连接
const reserved = await sql.reserve();

try {
  await reserved`INSERT INTO users (name) VALUES (${"Alice"})`;
} finally {
  // 必须释放连接回池
  reserved.release();
}

// 或使用 Symbol.dispose 自动释放
{
  using reserved = await sql.reserve();
  await reserved`SELECT 1`;
} // 自动释放
```

***

## 预处理语句

默认情况下，Bun 会自动为可判断为静态的查询创建命名预处理语句，提高性能。你可以在连接配置中设置 `prepare: false` 关闭此行为：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const sql = new SQL({
  // 其他配置...
  prepare: false, // 禁用服务端持久命名预处理语句
});
```

设置 `prepare: false` 后：

* 查询仍使用扩展协议，但使用[未命名预处理语句](https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY)，未命名预处理语句只存续到下一条解析未命名语句之前。
* 参数绑定仍然防止 SQL 注入
* 服务器每次都重新解析和规划查询
* 不支持查询流水线执行

应用场景：

* 使用 PGBouncer 事务模式（1.21.0 以后的版本如果配置正确已支持命名语句）
* 调试查询执行计划
* 动态 SQL 需频繁重新规划查询
* 不支持多条语句（除非用 `.simple()`）

禁止预处理语句会导致频繁执行时性能下降，因为服务器每次都要重新解析查询。

***

## 错误处理

客户端提供数据库特定的错误类型，继承自基础错误类：

### 错误类示例

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { SQL } from "bun";

try {
  await sql`SELECT * FROM users`;
} catch (error) {
  if (error instanceof SQL.PostgresError) {
    // PostgreSQL 专用错误
    console.log(error.code); // PostgreSQL 错误码
    console.log(error.detail); // 详细错误信息
    console.log(error.hint); // 提示
  } else if (error instanceof SQL.SQLiteError) {
    // SQLite 专用错误
    console.log(error.code); // SQLite 错误码（如 "SQLITE_CONSTRAINT"）
    console.log(error.errno); // SQLite 错误号
    console.log(error.byteOffset); // SQL 语句中的字节偏移（若有）
  } else if (error instanceof SQL.SQLError) {
    // 通用 SQL 错误（基类）
    console.log(error.message);
  }
}
```

<Accordion title="PostgreSQL 特定错误码">
  ### PostgreSQL 连接错误

  | 连接错误                              | 说明                                                                                                                                  |
  | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
  | `ERR_POSTGRES_CONNECTION_CLOSED`  | 已建立的连接被终止                                                                                                                           |
  | `ERR_POSTGRES_CONNECTION_FAILED`  | 连接已被接受，但在握手完成前就被关闭（例如服务器仍在启动中）。在查询等待期间会持续重试并进行退避，直到 `connectionTimeout`。注意：服务器在启动期间发送的错误（如 `57P03`）会表现为 `ERR_POSTGRES_SERVER_ERROR` |
  | `ERR_POSTGRES_CONNECTION_REFUSED` | 由于地址上没有服务在监听，连接被拒绝。会立即失败且不会重试                                                                                                       |
  | `ERR_POSTGRES_CONNECTION_TIMEOUT` | 在超时时间内未能建立连接                                                                                                                        |
  | `ERR_POSTGRES_IDLE_TIMEOUT`       | 因空闲而关闭连接                                                                                                                            |
  | `ERR_POSTGRES_LIFETIME_TIMEOUT`   | 连接超过最大存活时间                                                                                                                          |
  | `ERR_POSTGRES_TLS_NOT_AVAILABLE`  | SSL/TLS 连接不可用                                                                                                                       |
  | `ERR_POSTGRES_TLS_UPGRADE_FAILED` | 将连接升级为 SSL/TLS 失败                                                                                                                   |

  ### 认证错误

  | 错误码                                              | 说明                  |
  | ------------------------------------------------ | ------------------- |
  | `ERR_POSTGRES_AUTHENTICATION_FAILED_PBKDF2`      | 密码认证失败              |
  | `ERR_POSTGRES_UNKNOWN_AUTHENTICATION_METHOD`     | 服务器请求未知认证方法         |
  | `ERR_POSTGRES_UNSUPPORTED_AUTHENTICATION_METHOD` | 服务器请求不支持的认证方式       |
  | `ERR_POSTGRES_INVALID_SERVER_KEY`                | 认证时服务器密钥无效          |
  | `ERR_POSTGRES_INVALID_SERVER_SIGNATURE`          | 服务器签名无效             |
  | `ERR_POSTGRES_SASL_SIGNATURE_INVALID_BASE64`     | SASL 签名 Base64 编码错误 |
  | `ERR_POSTGRES_SASL_SIGNATURE_MISMATCH`           | SASL 签名验证失败         |

  ### 查询错误

  | 错误码                                  | 说明                        |
  | ------------------------------------ | ------------------------- |
  | `ERR_POSTGRES_SYNTAX_ERROR`          | SQL 语法错误（继承自 SyntaxError） |
  | `ERR_POSTGRES_SERVER_ERROR`          | PostgreSQL 服务器中的一般错误      |
  | `ERR_POSTGRES_INVALID_QUERY_BINDING` | 参数绑定错误                    |
  | `ERR_POSTGRES_QUERY_CANCELLED`       | 查询被取消                     |
  | `ERR_POSTGRES_NOT_TAGGED_CALL`       | 查询未使用标签调用                 |

  ### 数据类型错误

  | 错误码                                                     | 说明             |
  | ------------------------------------------------------- | -------------- |
  | `ERR_POSTGRES_INVALID_BINARY_DATA`                      | 二进制数据格式无效      |
  | `ERR_POSTGRES_INVALID_BYTE_SEQUENCE`                    | 字节序列无效         |
  | `ERR_POSTGRES_INVALID_BYTE_SEQUENCE_FOR_ENCODING`       | 编码错误           |
  | `ERR_POSTGRES_INVALID_CHARACTER`                        | 无效字符           |
  | `ERR_POSTGRES_OVERFLOW`                                 | 数值溢出           |
  | `ERR_POSTGRES_UNSUPPORTED_BYTEA_FORMAT`                 | 不支持的二进制格式      |
  | `ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE`                 | 整数大小不支持        |
  | `ERR_POSTGRES_MULTIDIMENSIONAL_ARRAY_NOT_SUPPORTED_YET` | 暂不支持多维数组       |
  | `ERR_POSTGRES_NULLS_IN_ARRAY_NOT_SUPPORTED_YET`         | 暂不支持数组中包含 NULL |

  ### 协议错误

  | 错误码                                     | 说明       |
  | --------------------------------------- | -------- |
  | `ERR_POSTGRES_EXPECTED_REQUEST`         | 期望客户端请求  |
  | `ERR_POSTGRES_EXPECTED_STATEMENT`       | 期望预处理语句  |
  | `ERR_POSTGRES_INVALID_BACKEND_KEY_DATA` | 后端密钥数据无效 |
  | `ERR_POSTGRES_INVALID_MESSAGE`          | 协议消息无效   |
  | `ERR_POSTGRES_INVALID_MESSAGE_LENGTH`   | 消息长度无效   |
  | `ERR_POSTGRES_UNEXPECTED_MESSAGE`       | 意外消息类型   |

  ### 事务错误

  | 错误码                                      | 说明         |
  | ---------------------------------------- | ---------- |
  | `ERR_POSTGRES_UNSAFE_TRANSACTION`        | 发现不安全的事务操作 |
  | `ERR_POSTGRES_INVALID_TRANSACTION_STATE` | 事务状态非法     |
</Accordion>

### SQLite 特有错误

SQLite 错误包含错误码和错误编号，参考 SQLite 标准错误码：

<Accordion title="常见 SQLite 错误码">
  | 错误码                 | errno | 说明              |
  | ------------------- | ----- | --------------- |
  | `SQLITE_CONSTRAINT` | 19    | 约束冲突（唯一、检查、非空等） |
  | `SQLITE_BUSY`       | 5     | 数据库正被锁定         |
  | `SQLITE_LOCKED`     | 6     | 表被锁             |
  | `SQLITE_READONLY`   | 8     | 试图写入只读数据库       |
  | `SQLITE_IOERR`      | 10    | 磁盘 I/O 错误       |
  | `SQLITE_CORRUPT`    | 11    | 数据库文件损坏         |
  | `SQLITE_FULL`       | 13    | 磁盘空间或数据库已满      |
  | `SQLITE_CANTOPEN`   | 14    | 无法打开数据库文件       |
  | `SQLITE_PROTOCOL`   | 15    | 数据库锁协议错误        |
  | `SQLITE_SCHEMA`     | 17    | 数据库结构已更改        |
  | `SQLITE_TOOBIG`     | 18    | 字符串或 BLOB 过长    |
  | `SQLITE_MISMATCH`   | 20    | 数据类型不匹配         |
  | `SQLITE_MISUSE`     | 21    | 错误使用 SQLite 库   |
  | `SQLITE_AUTH`       | 23    | 访问权限被拒绝         |

  错误处理示例：

  ```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
  const sqlite = new SQL("sqlite://app.db");

  try {
    await sqlite`INSERT INTO users (id, name) VALUES (1, 'Alice')`;
    await sqlite`INSERT INTO users (id, name) VALUES (1, 'Bob')`; // 主键重复
  } catch (error) {
    if (error instanceof SQL.SQLiteError) {
      if (error.code === "SQLITE_CONSTRAINT") {
        console.log("约束冲突:", error.message);
        // 处理唯一约束冲突
      }
    }
  }
  ```
</Accordion>

***

## 数字与 BigInt

Bun SQL 客户端特别处理超出 53 位整数范围的大数值。示例如下：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
import { sql } from "bun";

const [{ x, y }] = await sql`SELECT 9223372036854777 as x, 12345 as y`;

console.log(typeof x, x); // "字符串" "9223372036854777"
console.log(typeof y, y); // "数字" 12345
```

***

## 使用 BigInt 代替字符串

如需返回大整数为 `BigInt` 类型，可初始化时开启 `bigint` 选项：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const sql = new SQL({
  bigint: true,
});

const [{ x }] = await sql`SELECT 9223372036854777 as x`;

console.log(typeof x, x); // "bigint" 9223372036854777n
```

***

## 路线图

尚未完成的功能：

* 通过 Bun CLI `--db-preconnect` 标志实现连接预加载
* 列名转换（比如 `snake_case` 转 `camelCase`），受限于 C++ 中 WebKit `WTF::String` 对 unicode 字符转换支持
* 列类型转换

***

## 数据库特有功能

#### 认证方式

MySQL 支持多种认证插件，自动协商：

* **`mysql_native_password`** - 传统 MySQL 认证，兼容性好
* **`caching_sha2_password`** - MySQL 8.0+ 默认，更安全，使用 RSA 密钥交换
* **`sha256_password`** - 基于 SHA-256 的认证

客户端自动处理服务器请求切换认证插件，包括非 SSL 下的密码安全交换。

#### 预处理语句与性能

MySQL 对所有参数化查询使用服务端预处理语句：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 自动创建服务端预处理语句
const user = await mysql`SELECT * FROM users WHERE id = ${userId}`;

// 预处理语句缓存并重复使用
for (const id of userIds) {
  await mysql`SELECT * FROM users WHERE id = ${id}`; // 重用同一预处理语句
}

// 查询流水线 - 并行发送多个语句
const [users, orders, products] = await Promise.all([
  mysql`SELECT * FROM users WHERE active = ${true}`,
  mysql`SELECT * FROM orders WHERE status = ${"pending"}`,
  mysql`SELECT * FROM products WHERE in_stock = ${true}`,
]);
```

#### 多结果集

MySQL 支持多语句查询返回多个结果集：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
const mysql = new SQL("mysql://user:pass@localhost/mydb");

// 使用 simple() 多语句查询
const multiResults = await mysql`
  SELECT * FROM users WHERE id = 1;
  SELECT * FROM orders WHERE user_id = 1;
`.simple();
```

#### 字符集与排序规则

Bun.SQL 自动使用 MySQL `utf8mb4` 字符集，支持完整 Unicode（含 Emoji），为现代应用推荐。

#### 连接属性

Bun 自动向 MySQL 发送客户端信息，方便监控：

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 自动发送以下属性：
// _client_name: "Bun"
// _client_version: <bun 版本号>
// 可以在 MySQL performance_schema.session_connect_attrs 中查看
```

#### 类型处理

MySQL 类型映射到 JS 类型如下：

| MySQL 类型                                | JavaScript 类型            | 备注                                                           |
| --------------------------------------- | ------------------------ | ------------------------------------------------------------ |
| INT, TINYINT, MEDIUMINT                 | number                   | 在安全整数范围内                                                     |
| BIGINT                                  | string, number or BigInt | 如果值适合 i32/u32 大小，则为 number；否则根据 `bigint` 选项为 string 或 BigInt |
| DECIMAL, NUMERIC                        | string                   | 为保留精度                                                        |
| FLOAT, DOUBLE                           | number                   |                                                              |
| DATE                                    | Date                     | JavaScript Date 对象                                           |
| DATETIME, TIMESTAMP                     | Date                     | 按 UTC 解码（见下文说明）；`0000-00-00` 会变成无效日期                         |
| TIME                                    | number                   | 总微秒数                                                         |
| YEAR                                    | number                   |                                                              |
| CHAR, VARCHAR, VARSTRING, STRING        | string                   |                                                              |
| TINY TEXT, MEDIUM TEXT, TEXT, LONG TEXT | string                   |                                                              |
| TINY BLOB, MEDIUM BLOB, BLOG, LONG BLOB | string                   | BLOB 类型是 TEXT 类型的别名                                          |
| JSON                                    | object/array             | 自动解析                                                         |
| BIT(1)                                  | boolean                  | MySQL 中的 BIT(1)                                              |
| GEOMETRY                                | string                   | 几何数据                                                         |

`DATETIME` 和 `TIMESTAMP` 值在传输过程中不包含时区，因此 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 结果集

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
// 获取插入 ID
const result = await mysql`INSERT INTO users (name) VALUES (${"Alice"})`;
console.log(result.lastInsertRowid); // MySQL 的 LAST_INSERT_ID()

// 受影响的行数
const updated = await mysql`UPDATE users SET active = ${false} WHERE age < ${18}`;
console.log(updated.affectedRows); // 更新行数

// 使用 MySQL 专用函数
const now = await mysql`SELECT NOW() as current_time`;
const uuid = await mysql`SELECT UUID() as id`;
```

### MySQL 错误处理

```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
try {
  await mysql`INSERT INTO users (email) VALUES (${"duplicate@email.com"})`;
} catch (error) {
  if (error.code === "ER_DUP_ENTRY") {
    console.log("检测到重复条目");
  } else if (error.code === "ER_ACCESS_DENIED_ERROR") {
    console.log("访问被拒绝");
  } else if (error.code === "ER_BAD_DB_ERROR") {
    console.log("数据库不存在");
  }
  // MySQL 错误码与 mysql/mysql2 包兼容
}
```

### MySQL 性能优化建议

1. **使用连接池**：根据负载配置合理的 `max` 连接数
2. **启用预处理语句**：默认开启，提升性能
3. **批量操作用事务包裹**：关联查询放在同个事务里
4. **合理建立索引**：MySQL 查询性能依赖索引策略
5. **使用 `utf8mb4` 字符集**：默认启用，支持完整 Unicode 字符

## 常见问题

<AccordionGroup>
  <Accordion title="为什么叫 `Bun.sql` 而不是 `Bun.postgres`？">
    计划支持更多数据库驱动。现在已支持 MySQL，统一 API 支持 PostgreSQL、MySQL 和 SQLite。
  </Accordion>

  <Accordion title="如何知道当前使用的是哪个数据库适配器？">
    适配器根据连接字符串自动识别：

    * 以 `mysql://` 或 `mysql2://` 开头为 MySQL
    * 匹配 SQLite 格式（`:memory:`、`sqlite://`、`file://`）为 SQLite
    * 其他默认使用 PostgreSQL
  </Accordion>

  <Accordion title="MySQL 支持存储过程吗？">
    支持，包含 OUT 参数和多结果集：

    ```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
    // 调用存储过程
    const results = await mysql`CALL GetUserStats(${userId}, @total_orders)`;

    // 获取 OUT 参数
    const outParam = await mysql`SELECT @total_orders as total`;
    ```
  </Accordion>

  <Accordion title="可以使用 MySQL 特有语法吗？">
    当然，可以使用所有 MySQL 专属语法：

    ```ts theme={"theme":{"light":"github-light","dark":"dracula"}}
    // MySQL 特殊语法示例
    await mysql`SET @user_id = ${userId}`;
    await mysql`SHOW TABLES`;
    await mysql`DESCRIBE users`;
    await mysql`EXPLAIN SELECT * FROM users WHERE id = ${id}`;
    ```
  </Accordion>
</AccordionGroup>

***

## 为什么不直接用已有库？

npm 包如 postgres.js、pg 和 node-postgres 也可用于 Bun，都是不错的选择。

但有两个原因：

1. 我们认为集成内置数据库驱动对开发者更简单，减少寻找库的时间，让开发更高效。
2. 我们利用 JavaScriptCore 引擎内部特性，实现更快的对象创建，这在普通库中难以做到。

## 鸣谢

特别感谢 [@porsager](https://github.com/porsager) 的 [postgres.js](https://github.com/porsager/postgres) 对 API 接口设计的启发。
