Files
PR-Helper/docs/04-database-design.md
wonder 275e5cc886 docs: 添加 10 份技术文档,README 改为中文
- 01-architecture.md: 架构概览
- 02-backend-services.md: 后端服务层
- 03-frontend-interaction.md: 前端交互设计
- 04-database-design.md: 数据库设计
- 05-api-reference.md: API 接口文档
- 06-sse-streaming.md: SSE 流式传输
- 07-llm-integration.md: LLM 集成
- 08-deployment.md: 部署运维
- 09-development-guide.md: 开发指南
- 10-troubleshooting.md: 故障排查
2026-06-23 22:38:43 +08:00

8.8 KiB
Raw Permalink Blame History

数据库设计

概述

PR-Helper 使用 MySQL 作为主数据库,存储用户信息、仓库元数据、分析结果和审查笔记。

数据库配置

连接参数

MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=
MYSQL_DATABASE=pr_helper

DSN 格式

{user}:{password}@tcp({host}:{port})/{database}?charset=utf8mb4&parseTime=True&loc=Local

表结构

1. settings 表

全局键值存储,保存系统配置。

CREATE TABLE IF NOT EXISTS settings (
    `key`   VARCHAR(255) PRIMARY KEY,
    value   TEXT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段 类型 说明
key VARCHAR(255) 配置键名(主键)
value TEXT 配置值

默认设置

var DefaultSettings = map[string]string{
    "llm.endpoint":      "https://api.deepseek.com",
    "llm.api_key":       "",
    "llm.model":         "deepseek-v4-pro",
    "review.top_n":      "20",
    "review.concurrency": "5",
    "cache.max_age_days": "7",
    "cache.max_size_mb":  "5000",
}

2. users 表

用户账户信息。

CREATE TABLE IF NOT EXISTS users (
    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
    email         VARCHAR(255) NOT NULL UNIQUE,
    password_hash TEXT NOT NULL,
    created_at    DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at    DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段 类型 说明
id BIGINT 用户 ID(主键,自增)
email VARCHAR(255) 邮箱(唯一)
password_hash TEXT 密码哈希
created_at DATETIME 创建时间
updated_at DATETIME 更新时间

3. user_settings 表

用户个人设置,覆盖全局默认值。

CREATE TABLE IF NOT EXISTS user_settings (
    user_id BIGINT NOT NULL,
    `key`   VARCHAR(255) NOT NULL,
    value   TEXT NOT NULL,
    PRIMARY KEY (user_id, `key`),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段 类型 说明
user_id BIGINT 用户 ID(外键)
key VARCHAR(255) 配置键名
value TEXT 配置值

常用配置键

键名 说明 默认值
llm.endpoint LLM API 端点 https://api.deepseek.com
llm.api_key LLM API 密钥 (空)
llm.model LLM 模型名称 deepseek-v4-pro
review.top_n 审查文件数上限 20
review.concurrency 审查并发数 5

4. repositories 表

克隆的仓库元数据。

CREATE TABLE IF NOT EXISTS repositories (
    id         BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id    BIGINT,
    url        TEXT NOT NULL,
    local_path TEXT NOT NULL,
    size_bytes BIGINT DEFAULT 0,
    cloned_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    last_used  DATETIME DEFAULT CURRENT_TIMESTAMP,
    auth_type  VARCHAR(20) NOT NULL DEFAULT 'none',
    credential TEXT,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段 类型 说明
id BIGINT 仓库 ID(主键,自增)
user_id BIGINT 所有者用户 ID(外键)
url TEXT 仓库 URL
local_path TEXT 本地存储路径
size_bytes BIGINT 仓库大小(字节)
cloned_at DATETIME 克隆时间
last_used DATETIME 最后使用时间
auth_type VARCHAR(20) 认证类型(none/https/ssh)
credential TEXT 认证凭证(不明文返回)

5. analyses 表

分析结果存储(PR 描述和代码审查)。

CREATE TABLE IF NOT EXISTS analyses (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id     BIGINT,
    repo_id     BIGINT,
    type        VARCHAR(50) NOT NULL,
    base_ref    TEXT NOT NULL,
    head_ref    TEXT NOT NULL,
    result      LONGTEXT,
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    FOREIGN KEY (repo_id) REFERENCES repositories(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段 类型 说明
id BIGINT 分析 ID(主键,自增)
user_id BIGINT 用户 ID(外键)
repo_id BIGINT 仓库 ID(外键)
type VARCHAR(50) 类型(pr_description/code_review)
base_ref TEXT 基准分支
head_ref TEXT 目标分支
result LONGTEXT 结果 JSON
created_at DATETIME 创建时间

result 字段格式

PR 描述类型:

{
  "content": "# 标题\n\n## 概述\n..."
}

代码审查类型:

{
  "file_reviews": [
    {
      "file_name": "main.go",
      "change_lines": 42,
      "suggestions": [
        {
          "severity": "warning",
          "description": "...",
          "suggestion": "...",
          "code_example": "..."
        }
      ],
      "raw_review": "..."
    }
  ],
  "summary": {
    "score": 7,
    "overall": "...",
    "findings": "...",
    "recommendations": "..."
  },
  "top_n": 20
}

6. review_notes 表

用户添加的审查笔记。

CREATE TABLE IF NOT EXISTS review_notes (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id     BIGINT,
    analysis_id BIGINT,
    scope       VARCHAR(50) NOT NULL,
    scope_key   TEXT NOT NULL,
    content     TEXT NOT NULL,
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
    FOREIGN KEY (analysis_id) REFERENCES analyses(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
字段 类型 说明
id BIGINT 笔记 ID(主键,自增)
user_id BIGINT 用户 ID(外键)
analysis_id BIGINT 分析 ID(外键)
scope VARCHAR(50) 作用域类型
scope_key TEXT 作用域键
content TEXT 笔记内容
created_at DATETIME 创建时间
updated_at DATETIME 更新时间

scope 类型

scope scope_key 说明
overall (空) 整体审查笔记
file 文件名 文件级别笔记
suggestion 建议 ID 建议级别笔记

索引设计

主键索引

  • 所有表使用 BIGINT 自增主键
  • settings 表使用 key 作为主键

唯一索引

  • users.email: 唯一约束

复合主键

  • user_settings: (user_id, key)

外键索引

  • user_settings.user_id → users.id
  • repositories.user_id → users.id
  • analyses.user_id → users.id
  • analyses.repo_id → repositories.id
  • review_notes.user_id → users.id
  • review_notes.analysis_id → analyses.id

迁移策略

自动迁移

func (db *DB) migrate() error {
    stmts := []string{
        "CREATE TABLE IF NOT EXISTS ...",
        // ...
    }
    for _, s := range stmts {
        if _, err := db.conn.Exec(s); err != nil {
            return err
        }
    }
    return nil
}

增量迁移

alterStmts := []string{
    "ALTER TABLE repositories ADD COLUMN auth_type VARCHAR(20) NOT NULL DEFAULT 'none'",
    "ALTER TABLE repositories ADD COLUMN credential TEXT",
}
for _, s := range alterStmts {
    db.conn.Exec(s) // 忽略错误(列已存在)
}
  • 使用 IF NOT EXISTS 避免重复创建
  • 忽略 "duplicate column" 错误实现幂等性

默认数据初始化

func (db *DB) seedDefaults() error {
    for key, val := range models.DefaultSettings {
        _, err := db.conn.Exec(
            "INSERT IGNORE INTO settings (`key`, value) VALUES (?, ?)", key, val,
        )
        // ...
    }
    return nil
}
  • 使用 INSERT IGNORE 避免重复插入

数据完整性

外键约束

  • 级联删除(ON DELETE CASCADE)
  • 删除用户时自动清理相关数据

数据验证

  • 应用层验证(handler 层)
  • 数据库约束(NOT NULL, UNIQUE)

性能优化

查询优化

  • 使用参数化查询避免 SQL 注入
  • 避免 SELECT *,只查询需要的字段
  • 合理使用索引

连接管理

  • 使用 database/sql 连接池
  • 设置合理的连接超时
  • 及时关闭连接

大字段处理

  • result 使用 LONGTEXT
  • 考虑分表或外部存储(未来优化)

备份策略

逻辑备份

mysqldump -u root -p pr_helper > backup.sql

恢复

mysql -u root -p pr_helper < backup.sql

定期备份

  • 建议每日备份
  • 保留最近 7 天备份
  • 异地备份(生产环境)

监控

关键指标

  • 连接数
  • 查询耗时
  • 慢查询
  • 表大小

命令

-- 查看连接数
SHOW STATUS LIKE 'Threads_connected';

-- 查看慢查询
SHOW VARIABLES LIKE 'slow_query_log';

-- 查看表大小
SELECT table_name, round(((data_length + index_length) / 1024 / 1024), 2) AS "Size (MB)"
FROM information_schema.tables
WHERE table_schema = 'pr_helper';