Files
2026-10-20 21:53:26 +08:00

108 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 3.2 数据库建表
:::tip 概述
建表是模块开发的第一步。本项目对表结构有强约束:统一审计列、int 自增主键、del_flag 软删、uk_* 唯一索引、列注释枚举。这些规范不是建议——它们是全局钩子、字典系统、代码生成器正常工作的前提。
:::
## 统一规范(25 张表齐备)
```sql
-- 审计列(每张表必有)
id int NOT NULL AUTO_INCREMENT COMMENT '主键ID', -- 数据库自增(禁用雪花)
create_user varchar(50) DEFAULT '' COMMENT '创建人',
create_time datetime DEFAULT (now()) COMMENT '创建时间',
update_user varchar(50) DEFAULT '' COMMENT '更新人',
update_time datetime DEFAULT (now()) COMMENT '更新时间',
del_flag int DEFAULT 0 COMMENT '删除标志:0-正常 1-已删除',
-- 租户级表(9 张)另有:
tenant_id int DEFAULT 0 COMMENT '租户ID:0-平台级',
PRIMARY KEY (id)
```
关键决策(与直觉不同的点):
::: warning 关键约束
1. **主键统一 int 数据库自增**(2026-10-13 定稿):禁用雪花算法(`utility/id` 已删除);新增后用 `result.LastInsertId()` 回读;hooks 不填 id。
2. **删除一律软删**:deleteHook 把物理删除改写为 `UPDATE del_flag=1`,查询由 `dao.Ctx` 恒过滤 `del_flag=0`。
3. **无物理外键**:全部逻辑外键(如 article.category_id),跨表一致性由业务层保证。
:::
## 唯一索引(uk_*,13 个定稿)
唯一索引是并发唯一性的最终保证(`UniqueFields` 预检仅为 UX 层,存在 TOCTOU 竞态)。命名规范 `uk_` 前缀:
```sql
-- 示例:goframe_user 的三个唯一索引(均含 del_flag,软删行不占坑)
UNIQUE KEY uk_tenant_username (tenant_id, username, del_flag)
UNIQUE KEY uk_tenant_mobile (tenant_id, mobile, del_flag)
UNIQUE KEY uk_tenant_code (tenant_id, code, del_flag)
-- 全局唯一(平台级表)
UNIQUE KEY uk_code (code) -- config / dict / param / file_template / tenant
UNIQUE KEY uk_tenant_name (tenant_id, name, del_flag) -- dept / level / position / category
```
::: tip 索引范围纪律
含 tenant_id 的唯一索引,模块唯一预检(UniqueFields 的 `Group:"tenant_id"` 或手写检查按行现租户)**范围必须等于索引范围**,否则漏报 1062 或跨租户误报。
:::
## 列注释枚举(字典与生成器的数据源)
注释写法 `字段名:1-正常 2-禁用`(`-`、`—`、`=`、`=` 均可作分隔符),生成器解析为前端选项并自动建字典(编码规范 `{模块驼峰}_{字段驼峰}`):
```sql
status int DEFAULT 1 COMMENT '状态:1-正常 2-禁用',
-- 常见枚举定稿:
-- article.status 0-正常 1-下架
-- menu.type 0-菜单 1-权限节点
-- job.status 0-未发布 1-运行中 2-暂停
-- job.execute_policy 1-立即执行 2-执行一次 3-放弃执行
-- job.is_sync 1-同步 0-异步
-- role.data_scope 1-全部 2-本部门及以下 3-本部门 4-仅本人
-- login_log.log_type 1-登录 2-退出
```
## 案例演示表(goframe_example)
```sql
CREATE TABLE `goframe_example` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(100) NOT NULL DEFAULT '' COMMENT '案例名称',
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '案例图片',
`type` int NOT NULL DEFAULT 0 COMMENT '案例类型',
`status` int NOT NULL DEFAULT 1 COMMENT '状态:1-正常 2-禁用',
`sort` int NOT NULL DEFAULT 0 COMMENT '排序',
`create_user` varchar(50) NOT NULL DEFAULT '' COMMENT '创建人',
`create_time` datetime NULL DEFAULT (now()) COMMENT '创建时间',
`update_user` varchar(50) NOT NULL DEFAULT '' COMMENT '更新人',
`update_time` datetime NULL DEFAULT (now()) COMMENT '更新时间',
`del_flag` int NOT NULL DEFAULT 0 COMMENT '删除标志:0-正常 1-已删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='案例演示表';
```
它演示了最小可用表形态:审计列齐备、status 注释枚举(生成器据此自动创建 `example_status` 字典)、avatar 图片字段(注释含"图片"触发生成器图片识别)。
## 建表/变更工作流
```text
1) 以 document/mysql/ 定稿为基准补 ALTER
(含列注释枚举、uk_* 唯一索引;索引命名 uk_/idx_ 规范)
2) gf gen dao -c hack/config.yaml 刷新 dao/entity/do(service 手维护)
3) 同步 document/ 其余四方言脚本(人工校对)
4) 租户级表 → 修改 internal/model/hooks 的 tenantTables 清单
(生成器不自动维护此清单!)
5) go build ./... 重启;必要时 go run ./cmd/migrator 同步到其他环境库
```
## 租户级表判定
新增表是否带 `tenant_id` 决定它是否需要加入 `internal/model/hooks/hooks.go` 的 `tenantTables` 清单:
| 类型 | 现有表 | 行为 |
|------|--------|------|
| 租户级(9 张) | user/role/dept/level/position/article/category/notice/link | 自动过滤 `tenant_id IN(0,自身)`、插入自动盖章 |
| 平台级 | 其余 16 张 | 无租户过滤(超管可见全量) |
漏加清单的后果:租户级表不隔离,所有租户互相可见数据——务必同步。