hotime/docs/DatabaseDesign_数据库设计规范.md

409 lines
12 KiB
Markdown
Raw Normal View 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`,使用自增整数。
```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
- [ ] 选择字段注释格式正确(`标签:值-名称`