数据库迁移¶
数据库迁移管理 R Commerce 中的架构更改,允许您对数据库结构进行版本控制并在环境中一致地应用更改。
概述¶
R Commerce 使用基于 SQL 的迁移,具有以下特点:
- 版本控制 - 在 Git 中跟踪架构更改
- 可逆 - 每个迁移都有回滚能力
- 原子性 - 每个迁移在事务中运行
- 幂等 - 多次运行安全
启动时运行迁移¶
自动迁移¶
在配置中启用自动迁移:
[database]
url = "postgres://user:pass@localhost/rcommerce"
# 启动时运行待处理的迁移
run_migrations_on_startup = true
# 迁移设置
[migrations]
# 包含迁移文件的目录
path = "./migrations"
# 如果迁移失败则启动失败
strict = true
# 记录迁移执行
verbose = true
手动迁移¶
使用 CLI 手动运行迁移:
# 运行所有待处理的迁移
rcommerce db migrate
# 使用特定配置运行迁移
rcommerce db migrate -c /path/to/config.toml
# 检查迁移状态
rcommerce db status
# 查看待处理的迁移
rcommerce db pending
创建自定义迁移¶
迁移文件命名¶
迁移文件遵循以下命名约定:
示例:
迁移文件结构¶
每个迁移文件包含向上和向下迁移:
-- 向上迁移(应用更改)
-- 004_add_product_tags.sql
CREATE TABLE product_tags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
tag VARCHAR(100) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE(product_id, tag)
);
CREATE INDEX idx_product_tags_product_id ON product_tags(product_id);
CREATE INDEX idx_product_tags_tag ON product_tags(tag);
-- 向下迁移(回滚更改)
-- @DOWN
DROP INDEX IF EXISTS idx_product_tags_tag;
DROP INDEX IF EXISTS idx_product_tags_product_id;
DROP TABLE IF EXISTS product_tags;
迁移模板¶
使用 CLI 生成新迁移:
# 创建新的迁移文件
rcommerce db create-migration add_customer_loyalty_points
# 输出:Created migrations/005_add_customer_loyalty_points.sql
生成的模板:
迁移最佳实践¶
1. 保持迁移小巧¶
将大型更改拆分为多个迁移:
-- 005_create_order_items.sql
CREATE TABLE order_items (...);
-- 006_add_order_item_indexes.sql
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
2. 使迁移可逆¶
始终提供向下迁移:
-- 向上
ALTER TABLE customers ADD COLUMN phone VARCHAR(20);
-- @DOWN
ALTER TABLE customers DROP COLUMN IF EXISTS phone;
3. 处理现有数据¶
在架构更改中考虑数据迁移:
-- 添加带默认值的新列
ALTER TABLE products ADD COLUMN status VARCHAR(20) DEFAULT 'active';
-- 更新现有记录
UPDATE products SET status = 'active' WHERE status IS NULL;
-- 使列非空
ALTER TABLE products ALTER COLUMN status SET NOT NULL;
4. 使用事务¶
默认情况下迁移在事务中运行。对于无法在事务中运行的操作(如并发创建索引),使用:
5. 避免破坏性更改¶
不要删除列,而是考虑:
-- 而不是:ALTER TABLE products DROP COLUMN old_field;
-- 1. 添加弃用通知
COMMENT ON COLUMN products.old_field IS 'DEPRECATED: Will be removed in v2.0';
-- 2. 使可为空
ALTER TABLE products ALTER COLUMN old_field DROP NOT NULL;
-- 3. 在稍后迁移中删除
数据库重置程序¶
开发重置¶
将数据库重置为初始状态:
# 重置数据库(删除并重新创建)
rcommerce db reset
# 带新迁移重置
rcommerce db reset --with-migrations
# 重置并用测试数据填充
rcommerce db reset --seed
迁移回滚¶
回滚特定迁移:
# 回滚最后一个迁移
rcommerce db rollback
# 回滚特定数量的迁移
rcommerce db rollback --steps 3
-- 回滚到特定版本
rcommerce db rollback --to 003
-- 回滚特定迁移
rcommerce db rollback --migration 005_add_feature
强制迁移状态¶
在极少数情况下,您可能需要强制迁移状态:
-- 将迁移标记为已应用(不运行它)
rcommerce db force --version 005
-- 将迁移标记为待处理
rcommerce db unforce --version 005
-- 重置迁移跟踪(谨慎使用!)
rcommerce db reset-tracking
迁移最佳实践¶
开发工作流¶
-
在代码更改前创建迁移
-
先编写迁移
- 定义架构更改
-
在本地测试迁移
-
编写应用程序代码
-
使用新架构实现功能
-
测试迁移
-
提交迁移和代码
团队协作¶
迁移冲突¶
当两个开发人员创建相同版本的迁移时:
-- 检查迁移状态
rcommerce db status
-- 如果存在冲突,重新编号迁移
mv migrations/005_add_feature.sql migrations/006_add_feature.sql
-- 更新迁移跟踪
rcommerce db force --version 005
rcommerce db migrate
代码审查清单¶
- 迁移有向上和向下部分
- 迁移是可逆的
- 没有未经弃用的破坏性更改
- 为外键添加了索引
- 处理了数据迁移(如果需要)
- 迁移已在本地测试
生产部署¶
部署前¶
-
备份数据库
-
在暂存环境测试迁移
-
检查迁移持续时间
部署步骤¶
- 部署应用程序(禁用迁移)
- 手动运行迁移
- 验证迁移成功
- 启用应用程序流量
零停机迁移¶
对于大型表,使用非阻塞迁移:
-- @NO_TRANSACTION
-- 创建索引而不锁定表
CREATE INDEX CONCURRENTLY idx_orders_created_at ON orders(created_at);
添加不带默认值的列(快速):
-- 步骤 1:添加可为空的列(快速)
ALTER TABLE products ADD COLUMN new_feature BOOLEAN;
-- 步骤 2:在应用程序代码中设置默认值
-- 步骤 3:批量回填数据
-- 步骤 4:使非空(稍后迁移)
故障排除¶
迁移失败¶
"迁移已应用"
"迁移校验和不匹配"
-- 如果迁移在应用后被修改
rcommerce db verify --fix
-- 或重置并重新应用
rcommerce db rollback --to 004
rcommerce db migrate
"锁定超时"
常见问题¶
失败的迁移使数据库处于不一致状态:
-- 检查迁移状态
rcommerce db status
-- 回滚失败的迁移
rcommerce db rollback
-- 修复迁移文件
vim migrations/005_failed_migration.sql
-- 重试
rcommerce db migrate
长时间运行的迁移:
-- 监控进度
watch -n 5 'rcommerce db status'
-- 检查 PostgreSQL 活动
psql -c "SELECT * FROM pg_stat_activity WHERE state = 'active';"
迁移调试¶
启用详细日志:
查看迁移历史:
迁移参考¶
CLI 命令¶
| 命令 | 说明 |
|---|---|
rcommerce db migrate |
运行待处理的迁移 |
rcommerce db rollback |
回滚迁移 |
rcommerce db status |
显示迁移状态 |
rcommerce db pending |
列出待处理的迁移 |
rcommerce db history |
显示已应用的迁移 |
rcommerce db create-migration |
创建新的迁移文件 |
rcommerce db reset |
重置数据库 |
rcommerce db force |
强制迁移状态 |
rcommerce db verify |
验证迁移完整性 |
迁移元数据表¶
R Commerce 在 _migrations 表中跟踪迁移:
SELECT * FROM _migrations;
-- 输出:
-- version | name | applied_at
-- ---------+-------------------------+------------------------
-- 001 | initial_schema | 2024-01-01 00:00:00+00
-- 002 | add_user_preferences | 2024-01-02 00:00:00+00
-- 003 | create_inventory_table | 2024-01-03 00:00:00+00