MySQL
快速开始
使用 MySQL 蓝图为现有 Flue 项目添加持久化共享 MySQL 存储。在终端或你选择的编码智能体中运行以下命令:
flue add database mysql
概述
MySQL 蓝图会安装 @flue/mysql 和 mysql2,并在源代码根目录创建 db.ts。生成的适配器使用连接池进行普通查询,并为每个事务保持在一个签出的连接上:
import { mysql, type MysqlQuery } from '@flue/mysql';
import mysql2 from 'mysql2/promise';
const pool = mysql2.createPool(process.env.MYSQL_URL!);
const toRows = (result: unknown): Record<string, unknown>[] =>
Array.isArray(result) ? result.map((row) => ({ ...row })) : [];
export default mysql({
query: async (text, params = []) => {
const [result] = await pool.execute(text, params);
return toRows(result);
},
transaction: async <T>(fn: (tx: { query: MysqlQuery }) => Promise<T>) => {
const connection = await pool.getConnection();
await connection.beginTransaction();
// ...
},
close: () => pool.end(),
});Flue 在构建时发现适配器并将其连接到生成的 Node 服务器。启动时,它会创建并验证所需的 MySQL 8 InnoDB 表。规范的智能体对话、不可变附件和已接受的提交随后会在进程替换后得以保留。副本可以共享持久状态,但每个智能体实例仍然需要一个活动的 Node 所有者。应用业务数据仍由应用自行管理。此蓝图仅适用于 Node 目标,因为 Cloudflare 部署使用 Durable Object SQLite。
配置
| 变量 | 用途 |
|---|---|
MYSQL_URL | 必需 — MySQL 连接字符串,由你的数据库提供商提供。 |
驱动在运行时读取此值。通过你平台的密钥存储提供它,永远不要提交它,并在提供商需要时配置 mysql2 TLS 选项。对于本地开发,vite dev 会加载项目 .env 文件,而 flue run --env <file> 会加载任何 .env 格式的文件。
蓝图会安装 @flue/mysql 和 mysql2,然后在源代码根目录创建 db.ts。Flue 在构建时发现该文件,并将其连接到生成的 Node 服务器。
@flue/mysql 支持 Node.js 目标上的 MySQL 8 和 InnoDB。Cloudflare 目标会自动使用 Durable Object SQLite,并在构建时拒绝 db.ts。有关按目标的持久化信息,请参阅数据库。
使用自定义驱动
@flue/mysql 不捆绑生产驱动。它接受一个运行器,因此你的应用拥有连接池、TLS、凭证和连接生命周期。规范的 mysql2 运行器使用 pool.execute() 进行普通查询,每个回调事务使用一个签出的连接:
import { mysql, type MysqlQuery } from '@flue/mysql';
import mysql2 from 'mysql2/promise';
const pool = mysql2.createPool(process.env.MYSQL_URL!);
const toRows = (result: unknown): Record<string, unknown>[] =>
Array.isArray(result) ? result.map((row) => ({ ...row })) : [];
export default mysql({
query: async (text, params = []) => {
const [result] = await pool.execute(text, params);
return toRows(result);
},
transaction: async <T>(fn: (tx: { query: MysqlQuery }) => Promise<T>) => {
const connection = await pool.getConnection();
try {
await connection.beginTransaction();
const result = await fn({
query: async (text, params = []) => {
const [rows] = await connection.execute(text, params);
return toRows(rows);
},
});
await connection.commit();
return result;
} catch (error) {
await connection.rollback();
throw error;
} finally {
connection.release();
}
},
close: () => pool.end(),
});运行器使用 ? 占位符并返回普通行对象。事务回调中的每个查询都必须使用签出的连接;通过连接池发出这些调用可能会将工作转移到另一个连接,从而脱离事务。
迁移
适配器的 migrate() 钩子会在生成的 Node 服务器启动时自动运行。它会幂等地创建 Flue 的 flue_* 表,验证完整架构,然后标记其版本。所有事务表都使用 InnoDB。没有单独的迁移命令,由较新 Flue 版本写入的数据库会拒绝启动,而不是冒不兼容写入的风险。
存储内容
Flue 数据库存储运行时状态,而不是整个应用。
由 Flue 存储:
- 规范的智能体对话流和压缩记录;
- 不可变附件负载;
- 已接受的直接提示和
dispatch(...)提交; - 持久化提交声明、租约和结算记录。
不由 Flue 存储:
- 沙盒文件和已安装的依赖项;
- 外部 API 副作用;
- 应用拥有的业务数据;
- 提供商凭证或密钥。
有关恢复行为,请参阅持久性, 有关适配器契约,请参阅数据持久化 API。
何时选择 MySQL
当你的 Node 部署已经运行 MySQL 8,或者当替换进程和多个副本需要在 InnoDB 支持的数据库中存储持久化智能体状态时,请选择 MySQL。每个智能体实例保留一个活动所有者。对于单主机持久化,文件支持的 sqlite() 可能更简单。当 Postgres 是你现有的操作标准时,请选择 @flue/postgres,
或者对于 SQLite 和 libSQL 工作负载,请选择 @flue/libsql。