- 在 README.md 中新增数据库设计规范、代码生成配置规范和改进规划的文档链接 - 在 CacheDb 结构体中添加历史记录开关 HistorySet - 实现历史记录的写入逻辑,记录每次缓存的新增和修改 - 更新缓存的获取和设置方法,支持历史记录的管理 - 优化数据库表的初始化和迁移逻辑,确保历史表的创建与管理
12 KiB
数据库设计规范
本文档定义了 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. 外键智能匹配机制
代码生成器会按以下优先级自动匹配外键关联的表:
- 完全匹配:
user_id→ 查找user表 - 带前缀的完全匹配:如果没找到,尝试
user_id→ 查找sys_user表(默认前缀) - 去除字段前缀匹配:如果字段有前缀且找不到对应表,会去掉前缀匹配
示例:admin_user_id 字段的匹配过程:
- 先查找
admin_user表 → 如果存在,关联到admin_user表 - 如果不存在,去掉前缀查找
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_user 和 handle_user 表,代码生成器会自动将 audit_user_id 和 handle_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
- 选择字段注释格式正确(
标签:值-名称)