- 在 README.md 中新增数据库设计规范、代码生成配置规范和改进规划的文档链接 - 在 CacheDb 结构体中添加历史记录开关 HistorySet - 实现历史记录的写入逻辑,记录每次缓存的新增和修改 - 更新缓存的获取和设置方法,支持历史记录的管理 - 优化数据库表的初始化和迁移逻辑,确保历史表的创建与管理
409 lines
12 KiB
Markdown
409 lines
12 KiB
Markdown
# 数据库设计规范
|
||
|
||
本文档定义了 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`,使用自增整数。
|
||
|
||
```sql
|
||
`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` 表
|
||
|
||
**使用场景**:当一张表需要记录多个用户(如创建人、审核人、处理人)时:
|
||
|
||
```sql
|
||
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. 关联表冗余外键
|
||
|
||
关联表应包含必要的冗余外键便于查询:
|
||
|
||
```sql
|
||
-- 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` 的设计便于快速查询所有子级:
|
||
```sql
|
||
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管理"格式,便于在管理后台显示:
|
||
|
||
```sql
|
||
-- MySQL 表备注示例
|
||
CREATE TABLE `user` (
|
||
...
|
||
) COMMENT='用户管理';
|
||
|
||
CREATE TABLE `article` (
|
||
...
|
||
) COMMENT='文章管理';
|
||
|
||
CREATE TABLE `order` (
|
||
...
|
||
) COMMENT='订单管理';
|
||
```
|
||
|
||
### SQLite 表备注
|
||
|
||
SQLite 不支持表备注,代码生成器会使用表名作为默认显示名称。如需自定义,可在配置文件中手动设置 `label`(详见代码生成配置规范)。
|
||
|
||
---
|
||
|
||
## 字段注释规则
|
||
|
||
### 注释语法格式
|
||
|
||
字段注释支持以下格式组合:
|
||
|
||
```
|
||
显示名称:选项值 附加备注{前端提示}
|
||
```
|
||
|
||
| 部分 | 分隔符 | 用途 |
|
||
|------|--------|------|
|
||
| 显示名称 | 无 | 前端表单/列表的字段标签 |
|
||
| 选项值 | `:` 冒号 | select 类型的下拉选项(格式:`值-名称,值-名称`) |
|
||
| 附加备注 | 空格 | 仅在数据库中查看,不传递给前端 |
|
||
| 前端提示 | `{}` | 存储到 `ps` 字段,用于前端显示提示文字 |
|
||
|
||
### 选择类型字段
|
||
|
||
使用 `标签:值-名称,值-名称` 格式,代码生成器会自动解析为下拉选项:
|
||
|
||
```sql
|
||
`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-已拒绝'
|
||
```
|
||
|
||
### 普通字段
|
||
|
||
直接使用中文说明:
|
||
|
||
```sql
|
||
`name` varchar(50) DEFAULT NULL COMMENT '名称'
|
||
`phone` varchar(20) DEFAULT NULL COMMENT '手机号'
|
||
`email` varchar(100) DEFAULT NULL COMMENT '邮箱'
|
||
```
|
||
|
||
### 附加备注(空格后)
|
||
|
||
空格后的内容**不会传递给前端**,仅供数据库设计时参考:
|
||
|
||
```sql
|
||
`user_id` int(11) COMMENT '用户ID 关联user表的主键'
|
||
`amount` decimal(10,2) COMMENT '金额 单位为元,精确到分'
|
||
```
|
||
|
||
### 前端提示({}内)
|
||
|
||
`{}` 中的内容存储到 `ps` 字段,前端可用于显示输入提示:
|
||
|
||
```sql
|
||
`phone` varchar(20) COMMENT '手机号{请输入11位手机号}'
|
||
`email` varchar(100) COMMENT '邮箱{格式:xxx@xxx.com}'
|
||
`content` text COMMENT '内容{支持HTML格式}'
|
||
```
|
||
|
||
### 组合使用
|
||
|
||
```sql
|
||
-- 完整格式示例
|
||
`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
|
||
|
||
```sql
|
||
`state` int(2) DEFAULT '0' COMMENT '状态:0-正常,1-异常,2-隐藏',
|
||
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
|
||
`modify_time` datetime DEFAULT NULL COMMENT '变更时间',
|
||
```
|
||
|
||
### SQLite
|
||
|
||
```sql
|
||
"state" INTEGER DEFAULT 0, -- 状态:0-正常,1-异常,2-隐藏
|
||
"create_time" TEXT DEFAULT NULL, -- 创建日期
|
||
"modify_time" TEXT DEFAULT NULL, -- 变更时间
|
||
```
|
||
|
||
### PostgreSQL
|
||
|
||
```sql
|
||
"state" INTEGER DEFAULT 0, -- 状态:0-正常,1-异常,2-隐藏
|
||
"create_time" TIMESTAMP DEFAULT NULL, -- 创建日期
|
||
"modify_time" TIMESTAMP DEFAULT NULL, -- 变更时间
|
||
```
|
||
|
||
---
|
||
|
||
## 完整建表示例
|
||
|
||
### MySQL 示例
|
||
|
||
```sql
|
||
-- 用户表
|
||
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 示例
|
||
|
||
```sql
|
||
-- 用户表
|
||
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
|
||
- [ ] 选择字段注释格式正确(`标签:值-名称`)
|