数据库迁移规范
核心原则
数据库迁移必须使用 golang-migrate 工具,禁止使用 GORM AutoMigrate,确保数据库结构版本可控。
允许的做法
迁移工具
- 使用 golang-migrate 管理数据库迁移
- 使用 纯 SQL 文件,无 ORM 绑定
迁移文件命名
{version}_{description}.{direction}.sqlversion: 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.sqlCREATE 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 规范
| 项目 | 规范 | 示例 |
|---|---|---|
| 字符集 | utf8mb4 | DEFAULT CHARSET=utf8mb4 |
| 排序规则 | utf8mb4_unicode_ci | COLLATE=utf8mb4_unicode_ci |
| 存储引擎 | InnoDB | ENGINE=InnoDB |
| 主键类型 | BIGINT AUTO_INCREMENT | id BIGINT AUTO_INCREMENT PRIMARY KEY |
| 时间字段 | BIGINT | created_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;