Skip to content

数据库迁移规范

核心原则

数据库迁移必须使用 golang-migrate 工具,禁止使用 GORM AutoMigrate,确保数据库结构版本可控。

允许的做法

迁移工具

  • 使用 golang-migrate 管理数据库迁移
  • 使用 纯 SQL 文件,无 ORM 绑定

迁移文件命名

{version}_{description}.{direction}.sql
  • version: 6 位数字版本号(000001-999999)
  • description: 下划线分隔的英文描述
  • direction: up(执行)或 down(回滚)
✅ 正确
000001_create_users_table.up.sql
000001_create_users_table.down.sql
000002_create_products_table.up.sql
000002_create_products_table.down.sql
000017_alter_tasks_add_priority.up.sql
000017_alter_tasks_add_priority.down.sql

文件组织

backend/
└── database/
    └── migrations/
        ├── 000001_create_users_table.up.sql
        ├── 000001_create_users_table.down.sql
        ├── 000002_create_products_table.up.sql
        └── 000002_create_products_table.down.sql

CREATE TABLE 模板

sql
-- ✅ 正确 - 000001_create_users_table.up.sql
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '用户 ID',

    -- 业务字段
    name VARCHAR(100) NOT NULL COMMENT '用户名',
    email VARCHAR(255) NOT NULL COMMENT '邮箱',
    status VARCHAR(50) NOT NULL DEFAULT 'active' COMMENT '状态',

    -- 时间字段(BIGINT 存储 Unix 时间戳,秒)
    created_at BIGINT NOT NULL COMMENT '创建时间',
    updated_at BIGINT NOT NULL COMMENT '更新时间',
    deleted_at BIGINT DEFAULT NULL COMMENT '删除时间(软删除)',

    -- 索引定义
    UNIQUE KEY uk_email (email),
    INDEX idx_status (status),
    INDEX idx_deleted_at (deleted_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表';
sql
-- ✅ 正确 - 000001_create_users_table.down.sql
DROP TABLE IF EXISTS users;

ALTER TABLE 规范

sql
-- ✅ 正确 - 000017_alter_tasks_add_priority.up.sql
ALTER TABLE tasks
ADD COLUMN priority INT NOT NULL DEFAULT 0 COMMENT '优先级(0-10)' AFTER status;

ALTER TABLE tasks ADD INDEX idx_tasks_priority (priority);
sql
-- ✅ 正确 - 000017_alter_tasks_add_priority.down.sql
ALTER TABLE tasks DROP INDEX idx_tasks_priority;
ALTER TABLE tasks DROP COLUMN priority;

时间字段规范

强制使用 BIGINT 时间戳

sql
-- ✅ 正确
created_at BIGINT NOT NULL COMMENT '创建时间(Unix 秒)',
updated_at BIGINT NOT NULL COMMENT '更新时间(Unix 秒)',
deleted_at BIGINT DEFAULT NULL COMMENT '删除时间(Unix 秒,NULL 表示未删除)'

原因

  • 时区无关,避免跨时区问题
  • 数值类型,便于范围查询和排序
  • Go 的 time.Time.Unix() 直接支持

必须遵守的 SQL 规范

项目规范示例
字符集utf8mb4DEFAULT CHARSET=utf8mb4
排序规则utf8mb4_unicode_ciCOLLATE=utf8mb4_unicode_ci
存储引擎InnoDBENGINE=InnoDB
主键类型BIGINT AUTO_INCREMENTid BIGINT AUTO_INCREMENT PRIMARY KEY
时间字段BIGINTcreated_at BIGINT NOT NULL
字段注释必须添加COMMENT '字段说明'
表注释必须添加COMMENT='表说明'

禁止的做法

  • 禁止 使用 GORM AutoMigrate
  • 禁止 直接修改已应用的迁移文件
  • 禁止 在迁移中删除数据(使用软删除)
go
// ❌ 错误 - 禁止使用 AutoMigrate
db.AutoMigrate(&User{}, &Product{})
sql
-- ❌ 错误 - 禁止删除数据
DELETE FROM users WHERE created_at < '2024-01-01';

-- ✅ 正确 - 使用软删除
UPDATE users SET deleted_at = UNIX_TIMESTAMP() WHERE created_at < 1704067200;

迁移操作

安装 golang-migrate

bash
# macOS
brew install golang-migrate

# Linux
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.15.2/migrate.linux-amd64.tar.gz | tar xvz
sudo mv migrate /usr/local/bin/

# 验证
migrate -version

执行迁移

bash
# 定义连接(简化命令)
export DB_URL="mysql://root:password@tcp(localhost:3306)/database?charset=utf8mb4&parseTime=true"
export MIG_PATH="backend/database/migrations"

# 执行所有待迁移
migrate -path $MIG_PATH -database $DB_URL up

# 执行指定步数
migrate -path $MIG_PATH -database $DB_URL up 2

# 查看当前版本
migrate -path $MIG_PATH -database $DB_URL version

回滚迁移

bash
# 回滚一步
migrate -path $MIG_PATH -database $DB_URL down 1

# 回滚指定步数
migrate -path $MIG_PATH -database $DB_URL down 3

部署流程

bash
# 1. 完整备份数据库(生产环境必须)
mysqldump -u root -p --single-transaction smart_cat > backup_$(date +%Y%m%d_%H%M%S).sql

# 2. 执行迁移
migrate -path $MIG_PATH -database $DB_URL up

# 3. 验证版本
migrate -path $MIG_PATH -database $DB_URL version

特殊场景

数据种子

sql
-- ✅ 正确 - 000099_seed_admin_user.up.sql
INSERT INTO users (id, email, password, name, role, status, created_at, updated_at)
VALUES (1, 'admin@example.com', 'hashed_password', '管理员', 'admin', 'active', UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
sql
-- ✅ 正确 - 000099_seed_admin_user.down.sql
DELETE FROM users WHERE id = 1;

相关文档