hotime/docs/DatabaseDesign_数据库设计规范.md
hoteas 230dfc5a2b feat(cache): 增加历史记录功能和数据库设计规范
- 在 README.md 中新增数据库设计规范、代码生成配置规范和改进规划的文档链接
- 在 CacheDb 结构体中添加历史记录开关 HistorySet
- 实现历史记录的写入逻辑,记录每次缓存的新增和修改
- 更新缓存的获取和设置方法,支持历史记录的管理
- 优化数据库表的初始化和迁移逻辑,确保历史表的创建与管理
2026-01-25 05:14:18 +08:00

12 KiB
Raw Blame History

数据库设计规范

本文档定义了 HoTime 框架代码生成器所依赖的数据库设计规范。遵循这些规范可以确保代码生成器正确识别表关系、自动生成 CRUD 接口和管理后台。


表命名规则

1. 关于表名前缀

一般情况下没必要强行添加前缀分组,直接使用业务含义命名即可:

推荐user、org、role、article

可以使用前缀的场景:当项目较大、表较多时,可以用前缀进行模块分组(如 sys_cms_),代码生成器会根据 _ 分词自动将同前缀的表归为一组。

sys_user、sys_role、sys_org    → 自动归入 sys 分组
cms_article、cms_category      → 自动归入 cms 分组

使用前缀的注意事项

  • 必须遵循外键全局唯一性规则(见下文)
  • 前缀分组后,关联 ID 命名会更复杂,容易产生重复
  • 外键名不允许重复指向不同的表

2. 可使用简称

较长的表名可以使用常见简称:

全称 简称
organization org
category ctg
configuration config
administrator admin

3. 关联表命名

多对多关联表使用 主表_关联表 格式:

user_org      -- 用户与组织的关联
user_role     -- 用户与角色的关联
article_tag   -- 文章与标签的关联

字段命名规则

1. 主键字段

所有表的主键统一命名为 id,使用自增整数。

`id` int(11) NOT NULL AUTO_INCREMENT

2. 外键字段

外键使用 完整表名_id 格式:

user_id       -- 指向 user 表
org_id        -- 指向 org 表
role_id       -- 指向 role 表
app_category_id -- 指向 app_category 表

3. 关联表引用

引用关联表时使用 关联表名_id

user_org_id   -- 指向 user_org 表
user_role_id  -- 指向 user_role 表

4. 外键全局唯一性(重要)

每个 xxx_id 字段名必须全局唯一指向一张表,代码生成器通过 _id 后缀自动识别外键关系。

✅ 正确设计:
- user_id      只能指向 user 表
- org_id       只能指向 org 表
- user_org_id  只能指向 user_org 表
- sys_user_id  只能指向 sys_user 表(如果使用前缀分组)

❌ 错误设计:
- dd_id 作为"钉钉外部系统ID",但系统中存在 dd 表
  → 代码生成器会误判为指向 dd 表的外键
- 同时存在 user 表和 sys_user 表,都使用 user_id
  → 外键名重复,代码生成器无法正确识别

使用前缀分组时的外键命名

如果使用了表名前缀(如 sys_user),外键应使用完整表名:

表名 外键命名
sys_user sys_user_id
sys_org sys_org_id
cms_article cms_article_id

非外键业务标识字段:避免使用 xxx_id 格式

业务含义 错误命名 正确命名
设备唯一标识 device_id device_uuid / device_sn
钉钉用户ID dingtalk_user_id dt_user_id / dingtalk_uid
微信OpenID wechat_id wechat_openid
外部系统编号 external_id external_code / external_sn

5. 外键智能匹配机制

代码生成器会按以下优先级自动匹配外键关联的表:

  1. 完全匹配user_id → 查找 user
  2. 带前缀的完全匹配:如果没找到,尝试 user_id → 查找 sys_user 表(默认前缀)
  3. 去除字段前缀匹配:如果字段有前缀且找不到对应表,会去掉前缀匹配

示例admin_user_id 字段的匹配过程:

  1. 先查找 admin_user 表 → 如果存在,关联到 admin_user
  2. 如果不存在,去掉前缀查找 user 表 → 如果存在,关联到 user

使用场景:当一张表需要记录多个用户(如创建人、审核人、处理人)时:

CREATE TABLE `order` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `user_id` int(11) COMMENT '下单用户',
    `audit_user_id` int(11) COMMENT '审核人',
    `handle_user_id` int(11) COMMENT '处理人',
    ...
);

如果系统中没有 audit_userhandle_user 表,代码生成器会自动将 audit_user_idhandle_user_id 识别为指向 user 表的外键。

6. 关联表冗余外键

关联表应包含必要的冗余外键便于查询:

-- user_app 表(用户与应用的关联)
CREATE TABLE user_app (
    id int(11) NOT NULL AUTO_INCREMENT,
    user_id int(11) DEFAULT NULL COMMENT '用户ID',
    app_id int(11) DEFAULT NULL COMMENT '应用ID',
    app_category_id int(11) DEFAULT NULL COMMENT '应用分类ID冗余便于按分类查询',
    ...
);

7. 层级关系字段

树形结构的表使用以下字段:

字段 类型 说明
parent_id int 父级ID顶级为 NULL 或 0
parent_ids varchar(255) 完整层级路径,格式:,1,3,5,(从根到当前,逗号分隔)
level int 层级深度,从 0 开始

示例

id=1, parent_id=NULL, parent_ids=",1,",      level=0  -- 顶级
id=3, parent_id=1,    parent_ids=",1,3,",    level=1  -- 一级
id=5, parent_id=3,    parent_ids=",1,3,5,",  level=2  -- 二级

parent_ids 的设计便于快速查询所有子级:

SELECT * FROM org WHERE parent_ids LIKE '%,3,%'  -- 查询id=3的所有子级

时间字段类型

不同数据库使用对应的时间类型:

数据库 类型 示例
MySQL datetime 2024-01-15 10:30:00
SQLite TEXT 2024-01-15 10:30:00
PostgreSQL timestamp 2024-01-15 10:30:00

表注释规则

表备注命名建议

表备注建议使用"XX管理"格式,便于在管理后台显示:

-- MySQL 表备注示例
CREATE TABLE `user` (
    ...
) COMMENT='用户管理';

CREATE TABLE `article` (
    ...
) COMMENT='文章管理';

CREATE TABLE `order` (
    ...
) COMMENT='订单管理';

SQLite 表备注

SQLite 不支持表备注,代码生成器会使用表名作为默认显示名称。如需自定义,可在配置文件中手动设置 label(详见代码生成配置规范)。


字段注释规则

注释语法格式

字段注释支持以下格式组合:

显示名称:选项值 附加备注{前端提示}
部分 分隔符 用途
显示名称 前端表单/列表的字段标签
选项值 : 冒号 select 类型的下拉选项(格式:值-名称,值-名称
附加备注 空格 仅在数据库中查看,不传递给前端
前端提示 {} 存储到 ps 字段,用于前端显示提示文字

选择类型字段

使用 标签:值-名称,值-名称 格式,代码生成器会自动解析为下拉选项:

`state` int(2) DEFAULT '0' COMMENT '状态:0-正常,1-异常,2-隐藏'
`sex` int(1) DEFAULT '0' COMMENT '性别:0-未知,1-男,2-女'
`status` int(2) DEFAULT '0' COMMENT '审核状态:0-待审核,1-已通过,2-已拒绝'

普通字段

直接使用中文说明:

`name` varchar(50) DEFAULT NULL COMMENT '名称'
`phone` varchar(20) DEFAULT NULL COMMENT '手机号'
`email` varchar(100) DEFAULT NULL COMMENT '邮箱'

附加备注(空格后)

空格后的内容不会传递给前端,仅供数据库设计时参考:

`user_id` int(11) COMMENT '用户ID 关联user表的主键'
`amount` decimal(10,2) COMMENT '金额 单位为元,精确到分'

前端提示({}内)

{} 中的内容存储到 ps 字段,前端可用于显示输入提示:

`phone` varchar(20) COMMENT '手机号{请输入11位手机号}'
`email` varchar(100) COMMENT '邮箱{格式xxx@xxx.com}'
`content` text COMMENT '内容{支持HTML格式}'

组合使用

-- 完整格式示例
`status` int(2) DEFAULT '0' COMMENT '状态:0-待审核,1-已通过,2-已拒绝 业务状态流转字段{选择当前审核状态}'

解析结果:

  • label = "状态"
  • options = [{name:"待审核", value:"0"}, {name:"已通过", value:"1"}, {name:"已拒绝", value:"2"}]
  • ps = "选择当前审核状态"
  • 空格后的"业务状态流转字段"不会传递给前端

SQLite 字段备注

SQLite 不支持字段备注COMMENT代码生成器会使用字段名作为默认显示名称。如需自定义可在配置文件中手动设置详见代码生成配置规范


必有字段规则

每张业务表必须包含以下三个字段:

MySQL

`state` int(2) DEFAULT '0' COMMENT '状态:0-正常,1-异常,2-隐藏',
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
`modify_time` datetime DEFAULT NULL COMMENT '变更时间',

SQLite

"state" INTEGER DEFAULT 0,      -- 状态:0-正常,1-异常,2-隐藏
"create_time" TEXT DEFAULT NULL, -- 创建日期
"modify_time" TEXT DEFAULT NULL, -- 变更时间

PostgreSQL

"state" INTEGER DEFAULT 0,           -- 状态:0-正常,1-异常,2-隐藏
"create_time" TIMESTAMP DEFAULT NULL, -- 创建日期
"modify_time" TIMESTAMP DEFAULT NULL, -- 变更时间

完整建表示例

MySQL 示例

-- 用户表
CREATE TABLE `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `name` varchar(50) DEFAULT NULL COMMENT '用户名',
    `phone` varchar(20) DEFAULT NULL COMMENT '手机号',
    `password` varchar(64) DEFAULT NULL COMMENT '密码',
    `org_id` int(11) DEFAULT NULL COMMENT '组织ID',
    `role_id` int(11) DEFAULT NULL COMMENT '角色ID',
    `avatar` varchar(255) DEFAULT NULL COMMENT '头像',
    `sex` int(1) DEFAULT '0' COMMENT '性别:0-未知,1-男,2-女',
    `state` int(2) DEFAULT '0' COMMENT '状态:0-正常,1-异常,2-隐藏',
    `create_time` datetime DEFAULT NULL COMMENT '创建日期',
    `modify_time` datetime DEFAULT NULL COMMENT '变更时间',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 组织表(树形结构)
CREATE TABLE `org` (
    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `name` varchar(100) DEFAULT NULL COMMENT '组织名称',
    `parent_id` int(11) DEFAULT NULL COMMENT '父级ID',
    `parent_ids` varchar(255) DEFAULT NULL COMMENT '层级路径',
    `level` int(2) DEFAULT '0' COMMENT '层级深度',
    `sort` int(5) DEFAULT '0' COMMENT '排序',
    `state` int(2) DEFAULT '0' COMMENT '状态:0-正常,1-异常,2-隐藏',
    `create_time` datetime DEFAULT NULL COMMENT '创建日期',
    `modify_time` datetime DEFAULT NULL COMMENT '变更时间',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='组织表';

-- 用户组织关联表
CREATE TABLE `user_org` (
    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
    `user_id` int(11) DEFAULT NULL COMMENT '用户ID',
    `org_id` int(11) DEFAULT NULL COMMENT '组织ID',
    `state` int(2) DEFAULT '0' COMMENT '状态:0-正常,1-异常,2-隐藏',
    `create_time` datetime DEFAULT NULL COMMENT '创建日期',
    `modify_time` datetime DEFAULT NULL COMMENT '变更时间',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户组织关联表';

SQLite 示例

-- 用户表
CREATE TABLE "user" (
    "id" INTEGER PRIMARY KEY AUTOINCREMENT,
    "name" TEXT DEFAULT NULL,
    "phone" TEXT DEFAULT NULL,
    "password" TEXT DEFAULT NULL,
    "org_id" INTEGER DEFAULT NULL,
    "role_id" INTEGER DEFAULT NULL,
    "avatar" TEXT DEFAULT NULL,
    "sex" INTEGER DEFAULT 0,
    "state" INTEGER DEFAULT 0,
    "create_time" TEXT DEFAULT NULL,
    "modify_time" TEXT DEFAULT NULL
);

规范检查清单

在设计数据库时,请确认:

  • 表名无系统前缀
  • 主键统一为 id
  • 外键格式为 表名_id
  • 所有 xxx_id 字段都指向实际存在的表
  • 非外键业务标识不使用 xxx_id 格式
  • 树形表包含 parent_id、parent_ids、level
  • 所有表包含 state、create_time、modify_time
  • 选择字段注释格式正确(标签:值-名称