Files
Inbox/Go项目实战/01_数据模型建立/规范数据库设计 & 变更管理及工程流操作.md
2025-12-11 07:24:36 +08:00

184 lines
6.0 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.

---
tags: []
aliases:
- 🛠️ Database Engineering & Migration Standard (v1.0)
date created: 星期日, 十二月 7日 2025, 10:31:59 晚上
date modified: 星期二, 十二月 9日 2025, 10:14:44 晚上
---
# 🛠️ Database Engineering & Migration Standard (v1.0)
文档用途: 规范数据库设计、变更管理及工程流操作。
适用范围: 所有涉及 Schema 变更的后端开发任务。
核心原则: Code First (Logic) but SQL First (Schema). 严禁生产环境使用 ORM 自动建表。
---
## 1. 基础设施与工具链 (Infrastructure & Tools)
本项目采用 **“容器化数据库 + 版本化迁移工具”** 的架构。
| **组件** | **选型** | **说明** |
| --------------- | ------------------ | ----------------------------------------- |
| **Database** | **PostgreSQL 15+** | 运行于 Docker 容器中,保证开发/生产环境一致。 |
| **Schema Mgmt** | **Golang-Migrate** | CLI 工具,用于生成和执行版本化 SQL 脚本。 |
| **GUI Client** | **Navicat** | 推荐 Navicat / DataGrip / DBeaver仅用于设计和验证。 |
| **Automation** | **Make** | 封装常用命令,屏蔽底层复杂参数。 |
### 1.1 目录结构规范
Plaintext
```bash
project-root/
├── migrations/ # [Source of Truth] 存放所有 SQL 变更文件
│ ├── 000001_init_users.up.sql
│ └── 000001_init_users.down.sql
├── internal/
│ └── {domain}/ # 领域包
│ └── entity.go # [Code Mapping] GORM 结构体定义
├── docker-compose.yml # 定义本地 DB 容器
└── Makefile # 集成迁移命令
```
---
## 2. 数据库设计规范 (Design Standards)
### 2.1 命名约定
- **表名:** 必须使用**复数**形式,`snake_case` (e.g., `users`, `order_items`).
- **字段名:** 全小写,`snake_case` (e.g., `created_at`, `user_id`).
- **索引名:**
- 普通索引: `idx_tablename_column`
- 唯一索引: `uniq_tablename_column`
- **外键名:** `fk_tablename_ref_tablename`
### 2.2 关键字段约束
所有业务表**必须**包含以下基础字段:
```SQL
id BIGSERIAL PRIMARY KEY, -- 或 UUID
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ -- 仅在需要软删除时添加
```
### 2.3 设计禁忌
1. **严禁** 使用物理外键的级联删除 (`ON DELETE CASCADE`),除非是关联性极强的子表(如文章标签关联)。核心业务数据必须使用 `ON DELETE RESTRICT`
2. **严禁** 在涉及金额的字段使用 `FLOAT``DOUBLE`,必须使用 `DECIMAL``BIGINT` (分)。
3. **严禁**`NULL` 作为布尔值的第三种状态。布尔字段必须设置 `NOT NULL DEFAULT FALSE`
---
## 3. 标准作业流程 (SOP)
开发人员需严格遵循以下 **5 步闭环** 进行数据库变更:
### Step 1: 启动环境
确保本地 Docker 数据库正在运行。
```Bash
make network # 对应 docker-compose up -d
```
### Step 2: 创建迁移文件 (Create)
使用 Makefile 生成成对的 `.sql` 文件up/down
- `name` 参数应简短描述变更内容(如 `add_avatar_to_users`)。
```Bash
make new_migration name=init_schema
# 输出:
# Created migrations/000001_init_schema.up.sql
# Created migrations/000001_init_schema.down.sql
```
### Step 3: 编写 SQL (Edit)
- **UP 文件:** 填入 `CREATE TABLE`, `ALTER TABLE`, `CREATE INDEX` 等正向操作。
- _技巧:_ 可在 GUI 工具中设计好表结构,复制生成的 DDL 语句粘贴至此。
- **DOWN 文件:** 填入对应的回滚操作(如 `DROP TABLE`, `DROP INDEX`)。
### Step 4: 执行变更 (Apply)
将 SQL 应用到本地数据库。
```Bash
make migrate_up
```
_验证:_ 使用 GUI 工具连接数据库,确认表结构已更新。
### Step 5: 代码映射 (Mapping)
`internal/{domain}/entity.go` 中编写对应的 Go Struct。
- 确保 `gorm` tag 与数据库定义一致。
- 确保 `json` tag 符合 API 契约。
---
## 4. 自动化配置 (Automation)
将以下内容固化到项目根目录的 `Makefile` 中。
> **注意:** 确保 `DB_DSN` 与 `docker-compose.yml` 中的配置完全一致。
```Makefile
# ==============================================================================
# Database & Migration Logic
# ==============================================================================
# Database Connection String
# 格式: postgres://user:password@host:port/dbname?sslmode=disable
DB_DSN := postgres://postgres:secret@localhost:5432/cms_core?sslmode=disable
.PHONY: network new_migration migrate_up migrate_down migrate_force
# 1. 启动本地环境
network:
docker-compose up -d
# 2. 创建新的迁移文件 (Usage: make new_migration name=create_users)
new_migration:
@if [ -z "$(name)" ]; then echo "Error: name is required"; exit 1; fi
migrate create -ext sql -dir migrations -seq $(name)
# 3. 执行所有未执行的迁移 (Up)
migrate_up:
migrate -path migrations -database "$(DB_DSN)" up
# 4. 回滚上一次迁移 (Down 1 step)
migrate_down:
migrate -path migrations -database "$(DB_DSN)" down 1
# 5. 强制修复版本 (当 dirty database 时使用, version 为具体的版本号)
migrate_force:
migrate -path migrations -database "$(DB_DSN)" force $(version)
```
---
## 5. 故障排查 (Troubleshooting)
**Q: 执行 migrate_up 时报错 "Dirty database version x".**
- **原因:** 上一次迁移执行到一半失败了(可能是 SQL 语法错误),导致版本锁死。
- **解决:**
1. 手动修复 SQL 文件中的语法错误。
2. 执行 `make migrate_force version=x` (x 是失败前的那个版本号)。
3. 再次执行 `make migrate_up`
**Q: 多人协作时产生版本冲突。**
- **现象:** 你有一个 `0003_add_xx.up.sql`,同事提交代码后也有一个 `0003_add_yy.up.sql`
- **解决:** 重命名你的迁移文件编号为 `0004`,确保序列号在时间轴上是递增且唯一的。