跳到主要内容

数据库与本地代理

开通平台数据库后,每个 App 都有相互隔离的 Preview 和 Production 数据库。应用运行时直接读取 DATABASE_URL,不需要在源码中保存数据库地址、账号或密码。

Preview、Production 数据库分别在达到 5 GiB 时产生容量提醒。该值是软告警线,不会自动停止写入;文件类内容应使用 App Storage,而不是写入 MySQL。其他默认限制见资源与文件限制。

本地开发完成的数据库结构不是通过上传整库或手工登录 Production 上线,而是作为版本化 migration 与应用代码一起发布:deploy 先验证 Preview,promote --yes 再把同一批 migration 应用到 Production,成功后才切换应用版本。

应用连接数据库​

Node.js 和 Python 可以继续使用熟悉的数据库工具,例如 Prisma、Knex、Sequelize、SQLAlchemy 或 Alembic。SDK 不替代 ORM,也不要求使用某一种 ORM。

const databaseUrl = process.env.DATABASE_URL;
import os

database_url = os.environ["DATABASE_URL"]

应该把 SQL 整理成什么​

每次表结构变化都创建一个新的、有顺序的 migration 文件,并与实现该功能的代码放在同一次 Git 提交中。已经执行过的 migration 不再改写;需要修正时继续增加下一份 migration。

以下内容适合进入 migration:

  • 新建或修改表、字段、索引;
  • 为新功能准备少量、可重复写入的必要初始配置;
  • 分阶段兼容新旧代码的数据修复。

以下内容不会由平台自动从本地复制到 Production:

  • 本机或 Preview 中的测试数据;
  • 整库 SQL 导出、数据库备份;
  • 只在图形化客户端里手工执行、没有保存到项目的 SQL;
  • 大批量业务数据导入。

Node.js 目录示例​

使用 Prisma、Knex、Sequelize 等工具时,保留工具生成的 migration 目录。例如 Prisma 项目:

my-app/
├── prisma/
│ ├── schema.prisma
│ └── migrations/
│ ├── 20260918090000_init/migration.sql
│ └── 20260918103000_add_status/migration.sql
├── src/
├── package.json
├── package-lock.json
└── xdb-paas-deploy.yaml

先把 migration 工具作为项目依赖安装并提交锁文件:

npm install prisma @prisma/client

package.json 提供一个无需交互、执行完会自动退出的命令:

{
"scripts": {
"db:migrate": "prisma migrate deploy"
}
}

prisma/schema.prisma 从平台环境变量读取连接,不填写固定账号密码:

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}

然后在 xdb-paas-deploy.yaml 中声明:

database:
provider: mysql
migrate_command: npm run db:migrate

如果项目直接维护 .sql 文件,可以采用下面的结构:

my-app/
├── db/migrations/
│ ├── 001_create_customer_note.sql
│ └── 002_add_note_status.sql
├── scripts/migrate.mjs
├── package.json
└── xdb-paas-deploy.yaml

scripts/migrate.mjs 需要按文件名顺序执行尚未运行的文件,并把已完成版本写入项目自己的 migration 记录表;不要每次启动都无条件重放全部 SQL。对应命令可以配置为 node scripts/migrate.mjs。

Python 目录示例​

使用 Alembic 的项目通常保留下面这些文件:

my-app/
├── alembic/
│ ├── env.py
│ └── versions/
│ ├── 20260918_01_init.py
│ └── 20260918_02_add_status.py
├── alembic.ini
├── app/
├── requirements.txt
└── xdb-paas-deploy.yaml

requirements.txt 或 pyproject.toml 中声明 Alembic 和项目使用的 MySQL 驱动,并配置:

requirements.txt
alembic
SQLAlchemy
PyMySQL

alembic/env.py 读取平台连接串;使用 PyMySQL 时可把驱动名补到 URL 中:

import os
from alembic import context

config = context.config
database_url = os.environ["DATABASE_URL"]
config.set_main_option(
"sqlalchemy.url",
database_url.replace("mysql://", "mysql+pymysql://", 1),
)

再配置部署命令:

database:
provider: mysql
migrate_command: python -m alembic upgrade head

无论使用哪种语言,migration 工具、数据库驱动、migration 文件和锁文件都必须进入上传内容,命令不能依赖开发电脑全局安装的软件。

平台什么时候执行 migration​

完整发布顺序如下:

  1. xdbapp deploy 构建不可变版本;
  2. 平台向隔离 Job 注入 Preview DATABASE_URL,执行 migrate_command;
  3. migration 和 Preview 健康检查都成功后,返回 Preview URL;
  4. 验收后执行 xdbapp promote <deployment-id> --yes;
  5. 平台向隔离 Job 注入 Production DATABASE_URL,再次执行同一 migrate_command;
  6. Production migration 成功后,才启动新 Production 容器并切换流量。

因此客户不需要、也拿不到 Production RDS 的公网账号和密码。

迁移必须可重复且向前兼容

平台能保证 Production migration 报错时不切换应用流量,但 MySQL 已经成功执行的前半部分 SQL 不会自动撤销。修复后重试时,同一命令还会再次执行。

推荐使用 expand/contract:先新增表或字段,让新旧代码都能工作;完成切换并稳定运行后,再在后续版本清理旧结构。不要在同一次发布中直接删除旧版本仍依赖的字段。

xdbapp rollback 只回退应用代码和运行配置,不反向执行旧 migration,也不恢复业务数据。需要修复数据库时,应创建一份新的、向前执行的 migration。

本地验证 migration​

xdbapp dev -- 可以把 Preview DATABASE_URL 安全注入一个本地子进程,所以可以在发布前先运行同一命令:

# Node.js
xdbapp dev -- npm run db:migrate

# Python
xdbapp dev -- python -m alembic upgrade head

这一步连接的是 Preview 数据库,不是本机数据库,也不是 Production。之后 xdbapp deploy 仍会自动再执行一次,因此 migration 必须能识别已经完成的版本。

迁移失败时查看构建日志:

xdbapp inspect <deployment-id>
xdbapp logs --deployment <deployment-id> --type build

本地连接 Preview 数据库​

xdbapp db proxy

CLI 会在本机 127.0.0.1 打开一个临时端口,并通过加密通道连接平台内网中的 Preview 数据库。RDS 不需要开放公网。

命令会临时显示本地连接信息;按 Ctrl+C 后代理立即关闭。也可以指定本地端口:

xdbapp db proxy --port 13306

数据库代理只连接 Preview,不连接 Production,并且只接受通过商家后台登录获得的管理员或开发者凭据。普通部署令牌和 CI 令牌不能使用该能力。