Files
photography/backend/docs/DATABASE_MIGRATION.md
xujiang 84e778e033 feat: 完成数据库迁移系统开发
- 创建完整的迁移框架 (pkg/migration/)
- 版本管理系统,时间戳版本号 (YYYYMMDD_HHMMSS)
- 事务安全的上下迁移机制 (Up/Down)
- 迁移状态跟踪和记录 (migration_records 表)
- 命令行迁移工具 (cmd/migrate/main.go)
- 生产环境迁移脚本 (scripts/production-migrate.sh)
- 生产环境初始化脚本 (scripts/init-production-db.sh)
- 迁移测试脚本 (scripts/test-migration.sh)
- Makefile 集成 (migrate-up, migrate-down, migrate-status)
- 5个预定义迁移 (基础表、默认数据、元数据、收藏、用户资料)
- 自动备份机制、预览模式、详细日志
- 完整文档 (docs/DATABASE_MIGRATION.md)

任务13完成,项目完成率达到42.5%
2025-07-11 13:41:52 +08:00

414 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 数据库迁移系统文档
## 📋 概述
本项目使用自定义的数据库迁移系统,支持版本控制、回滚、备份等完整的数据库管理功能。该系统专为 SQLite 优化,同时兼容 MySQL 和 PostgreSQL。
## 🏗️ 系统架构
### 核心组件
```
pkg/migration/
├── migration.go # 迁移管理器核心逻辑
├── migrations.go # 所有迁移定义
└── README.md # 迁移开发指南
cmd/migrate/
└── main.go # 命令行工具
scripts/
├── production-migrate.sh # 生产环境迁移脚本
└── init-production-db.sh # 生产环境初始化脚本
```
### 迁移记录表
系统会自动创建 `schema_migrations` 表来跟踪迁移状态:
```sql
CREATE TABLE schema_migrations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
version VARCHAR(255) UNIQUE NOT NULL,
description VARCHAR(500),
applied BOOLEAN DEFAULT FALSE,
applied_at TIMESTAMP,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
```
## 🚀 快速开始
### 1. 开发环境初始化
```bash
# 初始化数据库(全新安装)
make db-init
# 查看迁移状态
make migrate-status
# 手动运行所有迁移
make migrate-up
```
### 2. 生产环境部署
```bash
# 全新生产环境初始化
./scripts/init-production-db.sh
# 生产环境迁移
./scripts/production-migrate.sh migrate
# 预览模式(不实际执行)
./scripts/production-migrate.sh -d migrate
```
## 📖 命令参考
### Makefile 命令
| 命令 | 描述 | 示例 |
|------|------|------|
| `migrate-status` | 查看迁移状态 | `make migrate-status` |
| `migrate-up` | 运行所有待处理迁移 | `make migrate-up` |
| `migrate-down` | 回滚指定步数迁移 | `make migrate-down STEPS=1` |
| `migrate-reset` | 重置整个数据库 | `make migrate-reset` |
| `migrate-create` | 创建新迁移模板 | `make migrate-create NAME=add_user_field` |
| `migrate-version` | 显示最新迁移版本 | `make migrate-version` |
| `db-init` | 初始化数据库 | `make db-init` |
| `db-backup` | 创建数据库备份 | `make db-backup` |
| `db-restore` | 恢复数据库备份 | `make db-restore BACKUP=filename` |
### 命令行工具
```bash
# 基本语法
go run cmd/migrate/main.go [选项] -c 命令
# 查看帮助
go run cmd/migrate/main.go -h
# 常用命令
go run cmd/migrate/main.go -c status # 查看状态
go run cmd/migrate/main.go -c up # 运行迁移
go run cmd/migrate/main.go -c down -s 1 # 回滚1步
go run cmd/migrate/main.go -c migrate -s 2 # 运行2个迁移
go run cmd/migrate/main.go -c version # 查看版本
```
### 生产环境脚本
```bash
# 基本语法
./scripts/production-migrate.sh [选项] 命令
# 常用命令
./scripts/production-migrate.sh status # 查看状态
./scripts/production-migrate.sh migrate # 执行迁移
./scripts/production-migrate.sh rollback 1 # 回滚1步
./scripts/production-migrate.sh backup # 创建备份
./scripts/production-migrate.sh check # 系统检查
# 预览模式
./scripts/production-migrate.sh -d migrate # 预览迁移
./scripts/production-migrate.sh -v status # 详细输出
./scripts/production-migrate.sh -f migrate # 强制执行
```
## 📝 迁移开发
### 迁移命名规范
```
版本号格式: YYYYMMDD_HHMMSS
示例: 20250111_120000
描述规范:
- 动词开头: Create, Add, Update, Remove, Drop
- 清晰简洁: Create user table, Add email index
- 避免缩写: 使用完整单词
```
### 创建新迁移
#### 方法1: 使用 Makefile
```bash
make migrate-create NAME="add_user_avatar_field"
```
#### 方法2: 手动添加到 migrations.go
```go
{
Version: "20250111_120000",
Description: "Add avatar field to user table",
Timestamp: time.Date(2025, 1, 11, 12, 0, 0, 0, time.UTC),
UpSQL: `
ALTER TABLE user ADD COLUMN avatar VARCHAR(255) DEFAULT '';
CREATE INDEX IF NOT EXISTS idx_user_avatar ON user(avatar);
`,
DownSQL: `
DROP INDEX IF EXISTS idx_user_avatar;
-- SQLite 不支持 DROP COLUMN需要重建表
CREATE TABLE user_temp AS SELECT id, username, password, email, status, created_at, updated_at FROM user;
DROP TABLE user;
ALTER TABLE user_temp RENAME TO user;
`,
},
```
### 迁移编写最佳实践
#### 1. UP 迁移 (向前)
```sql
-- ✅ 好的做法
ALTER TABLE user ADD COLUMN IF NOT EXISTS avatar VARCHAR(255) DEFAULT '';
CREATE INDEX IF NOT EXISTS idx_user_avatar ON user(avatar);
INSERT OR IGNORE INTO category (name) VALUES ('新分类');
-- ❌ 避免的做法
ALTER TABLE user ADD COLUMN avatar VARCHAR(255); -- 没有 IF NOT EXISTS
CREATE INDEX idx_user_avatar ON user(avatar); -- 没有 IF NOT EXISTS
INSERT INTO category (name) VALUES ('新分类'); -- 没有 OR IGNORE
```
#### 2. DOWN 迁移 (回滚)
```sql
-- SQLite 回滚模式(重建表)
CREATE TABLE user_temp (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
-- 注意:不包含新添加的 avatar 字段
status INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO user_temp (id, username, password, email, status, created_at, updated_at)
SELECT id, username, password, email, status, created_at, updated_at FROM user;
DROP TABLE user;
ALTER TABLE user_temp RENAME TO user;
-- 重新创建索引
CREATE INDEX IF NOT EXISTS idx_user_username ON user(username);
CREATE INDEX IF NOT EXISTS idx_user_email ON user(email);
```
#### 3. 数据迁移
```sql
-- 安全的数据迁移
UPDATE user SET status = 1 WHERE status IS NULL OR status = 0;
UPDATE photo SET category_id = 1 WHERE category_id IS NULL;
-- 避免危险操作
-- DELETE FROM user; -- 危险!不要直接删除数据
```
## 🔒 安全性和生产环境
### 备份策略
1. **自动备份**: 每次迁移前自动创建备份
2. **定期备份**: 通过 cron 定期备份
3. **备份验证**: 定期验证备份文件完整性
```bash
# 创建定期备份 cron 任务
0 2 * * * cd /path/to/project && make db-backup
# 验证备份
sqlite3 backup.db ".tables" > /dev/null && echo "备份正常" || echo "备份损坏"
```
### 生产环境部署流程
#### 1. 预生产测试
```bash
# 1. 在测试环境验证迁移
./scripts/production-migrate.sh -d migrate
# 2. 执行测试迁移
./scripts/production-migrate.sh migrate
# 3. 验证功能正常
make test
# 4. 回滚测试
./scripts/production-migrate.sh rollback 1
```
#### 2. 生产部署
```bash
# 1. 备份生产数据库
./scripts/production-migrate.sh backup
# 2. 执行迁移
./scripts/production-migrate.sh migrate
# 3. 验证迁移结果
./scripts/production-migrate.sh status
# 4. 重启应用服务
sudo systemctl restart photography-api
```
#### 3. 回滚计划
```bash
# 如果出现问题,立即回滚
./scripts/production-migrate.sh rollback 1
# 或者恢复备份
./scripts/production-migrate.sh restore backup_filename.db
```
### 监控和日志
```bash
# 查看迁移日志
tail -f migration.log
# 监控应用日志
tail -f backend.log
# 系统状态检查
./scripts/production-migrate.sh check
```
## 🛠️ 故障排除
### 常见问题
#### 1. 迁移失败
```bash
# 查看错误详情
go run cmd/migrate/main.go -c status
# 检查数据库连接
sqlite3 data/photography.db ".tables"
# 恢复到最近备份
make db-restore BACKUP=latest_backup.db
```
#### 2. 版本冲突
```bash
# 手动标记迁移为已应用
sqlite3 data/photography.db "UPDATE schema_migrations SET applied = 1 WHERE version = '20250111_120000';"
# 或者重置迁移状态
make migrate-reset
make migrate-up
```
#### 3. SQLite 限制
SQLite 不支持的操作和解决方案:
```sql
-- ❌ SQLite 不支持
ALTER TABLE user DROP COLUMN old_field;
ALTER TABLE user MODIFY COLUMN name VARCHAR(100);
-- ✅ 解决方案:重建表
CREATE TABLE user_new (...);
INSERT INTO user_new SELECT ... FROM user;
DROP TABLE user;
ALTER TABLE user_new RENAME TO user;
```
### 紧急恢复
#### 1. 完全重置
```bash
# 备份当前数据
cp data/photography.db data/emergency_backup.db
# 重置数据库
make migrate-reset
# 重新初始化
make db-init
```
#### 2. 数据恢复
```bash
# 从备份恢复数据
sqlite3 data/photography.db "
.read backup_data.sql
"
# 或者使用工具恢复
./scripts/production-migrate.sh restore backup_file.db
```
## 📊 性能优化
### 大型迁移优化
```sql
-- 分批处理大量数据
UPDATE user SET new_field = 'default' WHERE id BETWEEN 1 AND 1000;
UPDATE user SET new_field = 'default' WHERE id BETWEEN 1001 AND 2000;
-- ...
-- 使用事务
BEGIN TRANSACTION;
-- 批量操作
COMMIT;
```
### 索引策略
```sql
-- 先删除索引,再批量更新,最后重建索引
DROP INDEX IF EXISTS idx_user_email;
-- 批量更新操作
CREATE INDEX idx_user_email ON user(email);
```
## 📋 最佳实践总结
### ✅ 推荐做法
1. **版本控制**: 每个迁移都有唯一版本号
2. **可回滚**: 每个 UP 迁移都有对应的 DOWN 迁移
3. **幂等性**: 使用 `IF NOT EXISTS``OR IGNORE`
4. **备份**: 生产环境迁移前自动备份
5. **测试**: 在测试环境验证迁移
6. **监控**: 记录迁移日志和状态
### ❌ 避免做法
1. **直接修改**: 不要直接修改生产数据库
2. **删除迁移**: 不要删除已应用的迁移文件
3. **跳过版本**: 不要跳过中间版本
4. **无备份**: 不要在没有备份的情况下迁移
5. **大事务**: 避免长时间锁表的大事务
## 🔗 相关资源
- [SQLite 语法参考](https://sqlite.org/lang.html)
- [GORM 迁移指南](https://gorm.io/docs/migration.html)
- [数据库设计模式](https://en.wikipedia.org/wiki/Database_design)
- [迁移最佳实践](https://www.prisma.io/dataguide/types/relational/migration-best-practices)
---
**注意**: 在生产环境中进行数据库迁移时,请务必遵循最佳实践,确保数据安全。