Files
app-api/.qoder/repowiki/zh/content/数据库设计.md
T

36 KiB
Raw Blame History

数据库设计

**本文引用的文件** - [internal/model/brand.go](file://internal/model/brand.go) - [internal/model/model.go](file://internal/model/model.go) - [sql/model.sql](file://sql/model.sql) - [internal/repository/brand.go](file://internal/repository/brand.go) - [internal/repository/model.go](file://internal/repository/model.go) - [internal/handler/brand.go](file://internal/handler/brand.go) - [internal/handler/model.go](file://internal/handler/model.go) - [internal/config/config.go](file://internal/config/config.go) - [internal/config/database.go](file://internal/config/database.go) - [internal/config/meilisearch.go](file://internal/config/meilisearch.go) - [internal/config/redis.go](file://internal/config/redis.go) - [internal/database/mysql.go](file://internal/database/mysql.go) - [internal/cache/redis.go](file://internal/cache/redis.go) - [internal/search/meilisearch.go](file://internal/search/meilisearch.go) - [cmd/server/main.go](file://cmd/server/main.go) - [sql/user_device.sql](file://sql/user_device.sql) - [sql/user_active.sql](file://sql/user_active.sql) - [sql/ota.sql](file://sql/ota.sql) - [sql/black_list.sql](file://sql/black_list.sql) - [sql/ota_target_device.sql](file://sql/ota_target_device.sql) - [internal/model/user_device.go](file://internal/model/user_device.go) - [internal/model/user_active.go](file://internal/model/user_active.go) - [internal/model/ota.go](file://internal/model/ota.go) - [internal/repository/device.go](file://internal/repository/device.go) - [internal/repository/ota.go](file://internal/repository/ota.go) - [internal/handler/device.go](file://internal/handler/device.go) - [internal/handler/ota.go](file://internal/handler/ota.go) - [internal/task/device_persist.go](file://internal/task/device_persist.go)

更新摘要

所做更改

  • 更新OTA目标设备表结构:ota_target_device 表已简化,移除了 type 字段,现在仅包含 id、ota_id、mac_addr、create_at 字段
  • 更新实体关系图和字段定义以反映表结构简化
  • 更新数据访问模式和业务逻辑说明
  • 更新OTA升级子系统的实现细节

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向 Luxsin 应用 API 的数据库与数据模型,系统化梳理实体关系、字段定义、索引与约束、数据访问模式、缓存与搜索集成、性能优化、数据生命周期与迁移路径,并给出品牌(Brand)与型号(Model)实体的设计理念与业务逻辑说明。文档同时覆盖数据库连接配置、查询优化建议、数据安全与隐私要求以及访问控制要点。

更新 本次更新反映了 OTA 目标设备表结构的重大简化,移除了 type 字段,现在采用更简洁的单表架构设计,提高了数据库结构的简洁性和可维护性。

项目结构

本项目采用分层架构:入口程序负责初始化配置、数据库、搜索引擎与缓存;路由层组织 HTTP 接口;处理器层封装业务接口;仓库层实现数据访问;模型层承载数据结构;搜索与缓存模块作为外部依赖集成。

graph TB
subgraph "应用入口"
MAIN["cmd/server/main.go"]
end
subgraph "配置层"
CFG["internal/config/config.go"]
DB_CFG["internal/config/database.go"]
MS_CFG["internal/config/meilisearch.go"]
RD_CFG["internal/config/redis.go"]
end
subgraph "基础设施"
MYSQL["internal/database/mysql.go"]
REDIS["internal/cache/redis.go"]
MEILI["internal/search/meilisearch.go"]
end
subgraph "业务层"
ROUTER["路由(未在本文展开)"]
HANDLER_B["internal/handler/brand.go"]
HANDLER_M["internal/handler/model.go"]
HANDLER_D["internal/handler/device.go"]
HANDLER_O["internal/handler/ota.go"]
REPO_B["internal/repository/brand.go"]
REPO_M["internal/repository/model.go"]
REPO_D["internal/repository/device.go"]
REPO_O["internal/repository/ota.go"]
MODEL_B["internal/model/brand.go"]
MODEL_M["internal/model/model.go"]
MODEL_UD["internal/model/user_device.go"]
MODEL_UA["internal/model/user_active.go"]
MODEL_OTA["internal/model/ota.go"]
TASK_DP["internal/task/device_persist.go"]
end
MAIN --> CFG
CFG --> DB_CFG
CFG --> MS_CFG
CFG --> RD_CFG
MAIN --> MYSQL
MAIN --> REDIS
MAIN --> MEILI
ROUTER --> HANDLER_B
ROUTER --> HANDLER_M
ROUTER --> HANDLER_D
ROUTER --> HANDLER_O
HANDLER_B --> REPO_B
HANDLER_M --> REPO_M
HANDLER_D --> REPO_D
HANDLER_O --> REPO_O
REPO_B --> MODEL_B
REPO_M --> MODEL_M
REPO_D --> MODEL_UD
REPO_D --> MODEL_UA
REPO_O --> MODEL_OTA
TASK_DP --> REPO_D

图表来源

章节来源

核心组件

  • 数据库表 model:存储耳机型号信息,包含唯一组合索引以保证品牌+型号的唯一性。
  • 设备持久化表:user_device(设备信息持久化)、user_active(设备活跃度统计)
  • OTA 升级表:ota(固件升级信息)、black_list(黑名单)、ota_target_device(定向设备)
  • 模型对象 Brand 与 Model:分别映射品牌与型号的 JSON 字段与数据库列。
  • 仓库层:提供按品牌名或型号名检索的查询方法,支持模糊匹配与精确匹配。
  • 处理器层:暴露 HTTP 接口,支持返回 JSON 或 Base64 编码响应。
  • 配置层:集中加载数据库、搜索引擎与缓存的连接参数,并进行基本校验。
  • 基础设施:MySQL 连接池配置、Redis 客户端、Meilisearch 搜索客户端。

更新 OTA 目标设备表结构已简化,移除了 type 字段,现在采用更简洁的单表架构设计。

章节来源

架构总览

下图展示从 HTTP 请求到数据库与搜索引擎的调用链路,以及缓存的使用位置。新增了设备上报和 OTA 升级的完整处理流程。

sequenceDiagram
participant C as "客户端"
participant H as "处理器(品牌/型号/设备/OTA)"
participant R as "仓库(品牌/型号/设备/OTA)"
participant DB as "MySQL 数据库"
participant S as "Meilisearch"
participant RC as "Redis"
C->>H : "HTTP GET /brands,/models,/device/report,/audio/ota"
H->>R : "List(过滤条件)"
alt "数据库查询"
R->>DB : "执行 SQL 查询"
DB-->>R : "结果集"
else "搜索引擎查询"
H->>S : "SearchWithContext(key, attributes)"
S-->>H : "命中结果"
end
H-->>C : "JSON 或 Base64 响应"
note over H,RC : "可选:对热点数据进行缓存读写<br/>设备上报:Redis 缓存 + 定时持久化"

图表来源

详细组件分析

数据模型与实体关系

  • 实体:Brand(品牌)、Model(型号)、UserDevice(设备)、UserActive(活跃度)、OTA(固件升级)、BlackList(黑名单)、OTATargetDevice(定向设备)
  • 关系:
    • Model 通过字段 brand_name 引导与品牌的关系
    • UserDevice 与 UserActive 通过 mac_addr 关联
    • OTA 与 BlackList 通过 ota_id 关联
    • OTA 与 OTATargetDevice 通过 ota_id 关联
  • 字段与类型:
    • Brand:id(整数,主键)、name(字符串)
    • Modelid(整数,主键)、brand_name(字符串,非空)、name(字符串,非空)、form(字符串,可空)、rig(字符串,可空)、source(字符串,可空)、eq_key(字符串,可空)、create_at(时间戳,默认当前时间)
    • UserDeviceid(整数,主键)、mac_addr(字符串,唯一)、model(字符串)、add_time(时间戳,默认当前时间)、ver(字符串,可空)
    • UserActiveid(整数,主键)、mac_addr(字符串)、model(字符串)、active_date(日期,主键部分)、ip_addr(字符串)、create_at(时间戳,默认当前时间)
    • OTAid(整数,主键)、verCode(整数)、verName(字符串)、url(字符串)、md5(字符串)、force(整数,默认0)、desc(字符串,可空)、model(字符串,可空)、hw(整数,默认0)、target(整数,默认0)、beta(整数,默认0)、startTime(时间戳,可空)、endTime(时间戳,可空)、status(整数,默认1)
    • BlackListid(整数,主键)、ota_id(整数)、mac(字符串,默认空)、create_at(时间戳,默认当前时间)
    • OTATargetDeviceid(整数,主键)、ota_id(整数)、mac_addr(字符串)、create_at(时间戳,默认当前时间)

更新 OTA 目标设备表结构已简化,移除了 type 字段,现在采用更简洁的单表架构设计,type 字段不再存在于 ota_target_device 表中。

erDiagram
BRAND {
int id PK
string name
}
MODEL {
int id PK
string brand_name
string name
string form
string rig
string source
string eq_key
datetime create_at
}
USER_DEVICE {
int id PK
string mac_addr UK
string model
datetime add_time
string ver
}
USER_ACTIVE {
int id PK
string mac_addr
string model
date active_date PK
string ip_addr
datetime create_at
}
OTA {
int id PK
int verCode
string verName
string url
string md5
int force
string desc
string model
int hw
int target
int beta
datetime startTime
datetime endTime
int status
}
BLACK_LIST {
int id PK
int ota_id
string mac
datetime create_at
}
OTA_TARGET_DEVICE {
int id PK
int ota_id
string mac_addr
datetime create_at
}
BRAND ||--o{ MODEL : "拥有多个型号"
USER_DEVICE ||--o{ USER_ACTIVE : "每日活跃记录"
OTA ||--o{ BLACK_LIST : "黑名单关联"
OTA ||--o{ OTA_TARGET_DEVICE : "定向设备关联"

图表来源

章节来源

数据库表结构与约束

  • 表名:model、user_device、user_active、ota、black_list、ota_target_device
  • 主键:各表的 id 字段(自增整数)
  • 唯一索引:
    • model(brand_name, name)
    • user_device(mac_addr)
    • user_active(mac_addr, active_date)
  • 默认值:各表的 create_at 字段默认当前时间
  • 分区表:user_active 表按 active_date 进行范围分区,包含 170 个分区
  • 存储引擎与字符集:InnoDB、utf8mb4、排序规则 0900_ai_ci

更新 OTA 目标设备表结构已简化,移除了 type 字段,现在采用更简洁的单表架构设计。

章节来源

数据访问模式

  • 品牌列表:
    • 支持按品牌名模糊查询(LIKE %brandName%),无匹配时返回空数组
    • 结果按名称升序排列
  • 型号列表:
    • 支持按品牌名精确匹配或按型号名模糊匹配,二者二选一
    • 无匹配条件时返回空数组
    • 结果按名称升序排列
  • 设备持久化:
    • 设备上报:通过 Redis Hash 缓存设备信息
    • 定时持久化:每间隔时间从 Redis 读取并批量写入数据库
    • 支持设备首次注册和版本更新
  • OTA 升级:
    • 支持按型号、硬件版本、灰度标识查询最新 OTA 版本
    • 支持黑名单检查和定向设备检查
    • 自动处理灰度发布和强制升级逻辑
flowchart TD
Start(["进入仓库方法"]) --> CheckBrand["检查 brandName 是否为空"]
CheckBrand --> CheckModel["检查 modelName 是否为空"]
CheckModel --> Branch{"分支选择"}
Branch --> |brandName 非空| Q1["按品牌名精确匹配"]
Branch --> |modelName 非空| Q2["按型号名模糊匹配"]
Branch --> |均为空| Empty["返回空数组"]
Q1 --> Exec["执行查询并扫描结果"]
Q2 --> Exec
Empty --> End(["结束"])
subgraph "设备持久化流程"
Report["设备上报"] --> Cache["Redis 缓存"]
Cache --> Persist["定时持久化"]
Persist --> DBWrite["写入 user_device"]
DBWrite --> Active["写入 user_active"]
end

图表来源

章节来源

处理器与接口行为

  • 品牌接口:接收 query 参数 brandName,支持返回 JSON 或 Base64 编码响应
  • 型号接口:接收 query 参数 brandName 与 modelName,支持返回 JSON 或 Base64 编码响应
  • 设备上报接口:接收 mac、model、ver 参数,将设备信息缓存到 Redis
  • OTA 升级接口:接收 model、hw、mac、beta 参数,返回合适的 OTA 升级信息
  • 错误处理:内部错误统一返回 500 并记录日志

更新 OTA 接口现在使用简化的 OTA 目标设备表结构,不再需要处理 type 字段。

章节来源

搜索与缓存集成

  • 搜索:Meilisearch 客户端按给定关键字检索,限定返回属性,支持空命中返回空数组
  • 缓存:Redis 客户端初始化,用于设备信息缓存和定时持久化
  • 设备缓存:使用 Redis Hash 存储设备上报信息,键为设备 MAC 地址
  • 持久化策略:定时任务批量处理 Redis 缓存数据,避免频繁数据库写入

更新 OTA 缓存策略保持不变,但查询逻辑已简化。

章节来源

数据库连接配置

  • 加载顺序:环境变量优先于默认值;生产环境需提供密码
  • 连接参数:用户、主机、端口、数据库名、字符集、时区、超时等
  • 连接池:最大打开连接数、最大空闲连接数、连接最大生命周期
  • Ping 校验:启动时进行可达性检测

章节来源

配置与环境变量

  • 应用:APP_ENV、APP_HOST、APP_PORT
  • 数据库:DATABASE_HOST、DATABASE_PORT、DATABASE_NAME、DATABASE_USER、DATABASE_PASSWORD
  • 搜索引擎:MEILISEARCH_HOST、MEILISEARCH_API_KEY、MEILISEARCH_INDEX
  • 缓存:REDIS_HOST、REDIS_PORT、REDIS_DATABASE、REDIS_PASSWORD

章节来源

设备持久化子系统

  • 设备上报:客户端通过 /device/report 接口上报设备信息,包含 MAC 地址、设备型号、软件版本
  • Redis 缓存:设备信息以 JSON 格式存储在 Redis Hash 中,键为设备 MAC 地址
  • 定时持久化:后台任务每间隔时间从 Redis 读取设备数据,批量写入数据库
  • 数据一致性:支持设备首次注册和版本更新,自动处理 IP 地址更新

新增 设备持久化子系统提供了完整的设备生命周期管理能力。

章节来源

OTA 固件升级子系统

  • 版本查询:支持按型号、硬件版本、灰度标识查询最新可用 OTA 版本
  • 黑名单机制:支持将特定设备加入 OTA 升级黑名单
  • 定向升级:支持针对特定设备集合的定向升级策略
  • 灰度发布:通过 beta 标识实现渐进式升级发布
  • 强制升级:支持强制升级策略,阻止设备继续使用旧版本

更新 OTA 目标设备表结构已简化,移除了 type 字段,查询逻辑相应简化。

章节来源

依赖分析

  • 处理器依赖仓库;仓库依赖数据库;应用入口依赖配置与基础设施。
  • 搜索与缓存作为独立模块被配置层加载并在处理器中可选使用。
  • 设备持久化依赖 Redis 缓存和定时任务。
  • OTA 升级依赖复杂的业务逻辑和多表关联查询。
  • 代码内未发现循环依赖。
graph LR
MAIN["cmd/server/main.go"] --> CFG["internal/config/config.go"]
MAIN --> MYSQL["internal/database/mysql.go"]
MAIN --> REDIS["internal/cache/redis.go"]
MAIN --> MEILI["internal/search/meilisearch.go"]
HANDLER_B["internal/handler/brand.go"] --> REPO_B["internal/repository/brand.go"]
HANDLER_M["internal/handler/model.go"] --> REPO_M["internal/repository/model.go"]
HANDLER_D["internal/handler/device.go"] --> REPO_D["internal/repository/device.go"]
HANDLER_O["internal/handler/ota.go"] --> REPO_O["internal/repository/ota.go"]
REPO_B --> DB["sql/model.sql(表结构)"]
REPO_M --> DB
REPO_D --> DB_UD["sql/user_device.sql"]
REPO_D --> DB_UA["sql/user_active.sql"]
REPO_O --> DB_OTA["sql/ota.sql"]
REPO_O --> DB_BL["sql/black_list.sql"]
REPO_O --> DB_OTD["sql/ota_target_device.sql"]
TASK_DP["internal/task/device_persist.go"] --> REPO_D

图表来源

性能考虑

  • 连接池与生命周期
    • 最大打开连接数:25;最大空闲连接数:5;连接最大生命周期:5 分钟
    • 建议:根据并发与查询负载调整;生产环境结合监控指标动态优化
  • 查询优化
    • 品牌列表:支持模糊匹配,建议在高频搜索场景引入前缀索引或搜索引擎替代
    • 型号列表:按品牌名精确匹配或按型号名模糊匹配;建议对常用过滤字段建立合适索引
    • 设备查询:user_device 表的 mac_addr 唯一索引支持快速查找
    • OTA 查询:按 model、hw、beta、status 组合查询,建议建立复合索引
  • 缓存策略
    • 对品牌列表与热门型号列表进行短期缓存,设置合理过期时间
    • 设备信息使用 Redis 缓存,避免频繁数据库写入
    • 使用缓存穿透防护(空结果也缓存短时间)与缓存雪崩防护(随机过期时间)
  • 搜索优化
    • 使用搜索引擎进行全文检索与高亮,减少数据库 LIKE 查询压力
    • 控制返回字段数量,避免传输冗余数据
  • I/O 与序列化
    • 响应支持 Base64 编码,适合二进制传输场景,但会增加 CPU 开销
  • 分区表优化
    • user_active 表按日期分区,提高大数据量下的查询性能
    • 分区裁剪可以显著减少扫描数据量

更新 OTA 查询逻辑已简化,减少了不必要的字段扫描,提高了查询效率。

章节来源

故障排查指南

  • 数据库连接失败
    • 检查环境变量是否正确设置;确认主机、端口、用户名、密码与数据库名
    • 启动时会进行 Ping 校验,失败会记录错误并退出
  • 查询异常
    • 仓库层对扫描与迭代过程进行错误包装,定位具体阶段(扫描、迭代)
    • 建议开启数据库慢查询日志与应用日志聚合
  • 搜索与缓存
    • 搜索引擎与缓存客户端初始化后会记录连接信息;若无响应,检查主机、密钥与网络连通性
    • Redis 缓存异常会影响设备持久化功能
  • 响应编码
    • Base64 返回失败时,检查编码流程与日志输出
  • 设备持久化问题
    • 检查 Redis 连接状态和设备缓存数据
    • 定时任务执行失败时,查看任务日志和数据库连接状态
  • OTA 升级问题
    • 检查 OTA 表数据完整性和索引状态
    • 验证黑名单和定向设备表的数据准确性

更新 OTA 故障排查已简化,不再需要检查 type 字段。

章节来源

结论

本设计以简洁的表结构与清晰的分层架构支撑品牌与型号的查询需求。通过搜索引擎与缓存提升检索性能,配合连接池与错误处理机制保障稳定性。更新 OTA 目标设备表结构的简化显著提高了数据库的简洁性和可维护性,移除了 type 字段,现在采用更简洁的单表架构设计。新增的设备持久化和 OTA 固件升级子系统进一步完善了系统的业务能力,通过 Redis 缓存和分区表优化提升了大规模数据处理的性能。后续可在索引策略、缓存策略与数据迁移方面进一步细化,以满足生产环境的高可用与高性能要求。

附录

数据验证与业务规则

  • 品牌与型号名称必填,型号表对品牌+型号建立唯一索引,防止重复
  • 设备 MAC 地址唯一,支持设备去重和版本跟踪
  • OTA 升级记录包含版本号、MD5 校验、时间范围等完整性约束
  • 黑名单和定向设备表确保 OTA 发布的安全性
  • 时间字段 create_at 默认当前时间,便于审计与排序
  • 处理器层对空结果返回空数组,避免无效数据传播

更新 OTA 数据验证规则已简化,不再需要验证 type 字段。

章节来源

示例数据

  • 品牌示例:id=1, name="Sony"
  • 型号示例:id=1001, brand_name="Sony", name="WH-1000XM4", form="头戴式", rig="主动降噪", source="官方", eq_key="sony_xm4", create_at="2026-01-01 12:00:00"
  • 设备示例:id=1214, mac_addr="AA:BB:CC:DD:EE:FF", model="WH-1000XM4", add_time="2026-05-28 17:08:30", ver="1.2.3"
  • OTA 示例:id=48, verCode=100, verName="v1.2.3", url="http://example.com/firmware.bin", md5="d41d8cd98f00b204e9800998ecf8427e", force=1, desc="重大安全更新", model="WH-1000XM4", hw=1, target=1, beta=0, status=1

更新 OTA 示例数据已简化,移除了 type 字段。

章节来源

数据生命周期、保留策略与归档规则

  • 建议:基于 create_at 建立分区或定期归档任务,清理长期未使用的型号数据
  • 设备数据:保留最近 30 天的设备活跃记录,历史数据可压缩存储
  • OTA 数据:保留最近 6 个月的升级记录,历史版本可归档
  • 归档策略:保留近一年的活跃型号,历史数据移至冷存储
  • 审计:保留变更日志与备份周期,确保可追溯性

更新 OTA 数据生命周期管理保持不变,但查询逻辑已简化。

章节来源

数据迁移路径与版本管理

  • 版本化:每次结构变更生成迁移脚本,记录变更人、时间与目的
  • 回滚:保留逆向迁移脚本;灰度发布逐步切换
  • 兼容:新增字段采用可空策略,旧数据默认值填充
  • 设备数据迁移:支持从临时表导入到正式表,处理重复数据
  • OTA 数据迁移:支持版本号递增和兼容性检查

更新 OTA 数据迁移已简化,不需要处理 type 字段的迁移。

章节来源

数据安全、隐私要求与访问控制

  • 网络安全:数据库与搜索引擎通过内网或 VPC 访问,限制入站 IP
  • 凭证管理:敏感信息通过环境变量注入,禁止硬编码
  • 访问控制:最小权限原则;数据库账号仅授予必要权限;搜索引擎 API Key 严格管理
  • 设备隐私:MAC 地址等个人标识信息需遵循隐私保护法规
  • OTA 安全:固件 MD5 校验确保下载完整性,黑名单机制防止恶意设备升级

更新 OTA 安全机制保持不变,但查询逻辑已简化。

章节来源

品牌与型号实体设计理念

  • 品牌(Brand):最小可用模型,仅包含标识与名称,便于快速检索与展示
  • 型号(Model):承载产品特性字段(form、rig、source、eq_key),并与品牌建立弱关联,利于扩展与维护
  • 业务逻辑:通过仓库层的过滤条件实现灵活查询;处理器层统一响应格式,支持 Base64 编码

章节来源

设备持久化与 OTA 升级设计理念

  • 设备持久化:通过 Redis 缓存实现高并发设备上报,定时任务批量持久化降低数据库压力
  • OTA 升级:支持灰度发布、强制升级、定向升级等多种发布策略,确保升级过程可控
  • 数据一致性:通过唯一索引和事务保证数据完整性,通过分区表优化查询性能
  • 可扩展性:模块化设计支持功能扩展,预留接口便于新业务场景接入

更新 OTA 设计理念保持不变,但实现逻辑已简化。

章节来源