d0771597a6
- 添加前端设计文档(rui-admin、收银系统、模块打包) - 添加前端实施计划(收银后台功能完善) - 添加通用规范(API、编码、数据库、前端开发规则) - 建立文档索引和使用指南
1169 lines
42 KiB
Markdown
1169 lines
42 KiB
Markdown
# 数据库设计规范分析报告
|
||
|
||
> 基于对当前 spring-ai 项目数据库设计的全面审查,本报告列出所有不合理之处及专业改进方案。
|
||
> **注意:本报告仅做分析,不做任何代码实施。**
|
||
|
||
---
|
||
|
||
## 一、当前表清单(12张表)
|
||
|
||
| 序号 | SQL 表名 | 实体类 | 服务模块 | 状态 |
|
||
|------|---------|--------|---------|------|
|
||
| 1 | rui_system_oauth2_client | SystemOAuth2Client | system | 实体与SQL不一致 |
|
||
| 2 | rui_system_tenant | SystemTenant | system | 实体与SQL不一致 |
|
||
| 3 | rui_user_credential | UserCredential | user | 实体与SQL不一致 |
|
||
| 4 | rui_user_info | UserInfo | user | 一致 |
|
||
| 5 | rui_user_level | UserLevel | user | 一致 |
|
||
| 6 | rui_user_level_log | UserLevelLog | user | 一致 |
|
||
| 7 | rui_user_role | 无实体类 | user | 缺失实体 |
|
||
| 8 | rui_system_menu | 无实体类 | system | 缺失实体 |
|
||
| 9 | rui_system_role | 无实体类 | system | 缺失实体 |
|
||
| 10 | rui_system_role_menu | 无实体类 | system | 缺失实体 |
|
||
| 11 | rui_system_dict | 无实体类 | system | 缺失实体 |
|
||
| 12 | rui_system_config | 无实体类 | system | 缺失实体 |
|
||
|
||
---
|
||
|
||
## 二、严重问题(必须修改)
|
||
|
||
### 2.1 【致命】实体类表名与 SQL 表名严重不一致
|
||
|
||
**问题描述**:
|
||
```
|
||
SQL 表名: rui_system_oauth2_client
|
||
实体 @TableName: auth_oauth2_client
|
||
keepGlobalPrefix=true → 实际查找表: rui_auth_oauth2_client
|
||
结果: ❌ 找不到表!
|
||
|
||
SQL 表名: rui_system_tenant
|
||
实体 @TableName: auth_tenant
|
||
keepGlobalPrefix=true → 实际查找表: rui_auth_tenant
|
||
结果: ❌ 找不到表!
|
||
|
||
SQL 表名: rui_user_credential
|
||
实体 @TableName: auth_user
|
||
keepGlobalPrefix=true → 实际查找表: rui_auth_user
|
||
结果: ❌ 找不到表!
|
||
```
|
||
|
||
**影响**:
|
||
- 程序运行时无法找到正确的表,导致查询失败
|
||
- 表前缀 `rui_` 与模块前缀 `system_`/`user_` 混合使用,逻辑混乱
|
||
|
||
**专业方案**:
|
||
```
|
||
方案A:统一表前缀(推荐)
|
||
- 全局表前缀: rui_
|
||
- SQL表名: rui_oauth2_client / rui_tenant / rui_user
|
||
- 实体 @TableName: oauth2_client / tenant / user
|
||
- keepGlobalPrefix=true → rui_ + value = 正确
|
||
|
||
方案B:分模块前缀
|
||
- SQL表名保持: rui_system_oauth2_client / rui_user_credential
|
||
- 实体 @TableName: system_oauth2_client / user_credential
|
||
- keepGlobalPrefix=true → rui_ + value = 正确
|
||
|
||
方案C:去掉 keepGlobalPrefix,显式写全表名
|
||
- 实体 @TableName: rui_system_oauth2_client(不推荐,硬编码前缀)
|
||
```
|
||
|
||
**推荐采用方案A**,理由:
|
||
1. 表前缀仅用于标识项目/公司(rui_),不包含模块信息
|
||
2. 模块信息体现在表名本身(oauth2_client 在 system 服务下)
|
||
3. 与全局配置 `mybatis-plus.global-config.db-config.table-prefix: rui_` 一致
|
||
4. 租户过滤时 normalizeTableName 剥离 rui_ 后得到正确表名
|
||
|
||
---
|
||
|
||
### 2.2 【严重】缺少 6 个实体类
|
||
|
||
**问题描述**:以下表在 SQL 中已定义,但没有对应的 Java 实体类
|
||
|
||
| 表名 | 用途 | 影响 |
|
||
|------|------|------|
|
||
| rui_user_role | 用户角色关联 | 无法通过 MyBatis Plus 操作 |
|
||
| rui_system_menu | 菜单管理 | 无法通过 MyBatis Plus 操作 |
|
||
| rui_system_role | 角色管理 | 无法通过 MyBatis Plus 操作 |
|
||
| rui_system_role_menu | 角色菜单关联 | 无法通过 MyBatis Plus 操作 |
|
||
| rui_system_dict | 数据字典 | 无法通过 MyBatis Plus 操作 |
|
||
| rui_system_config | 系统配置 | 无法通过 MyBatis Plus 操作 |
|
||
|
||
**专业方案**:
|
||
- 为每张表创建对应的 Entity、Mapper、Service、Controller
|
||
- 或者至少创建 Entity + Mapper 用于基础 CRUD
|
||
|
||
---
|
||
|
||
### 2.3 【严重】主键策略不统一
|
||
|
||
**问题描述**:
|
||
```java
|
||
UserCredential: @TableId(type = IdType.ASSIGN_ID) // 雪花算法
|
||
其他所有实体: @TableId(type = IdType.AUTO) // 数据库自增
|
||
```
|
||
|
||
**SQL 中的问题**:
|
||
```sql
|
||
-- 有 AUTO_INCREMENT
|
||
rui_system_tenant: id BIGINT NOT NULL AUTO_INCREMENT
|
||
|
||
-- 没有 AUTO_INCREMENT
|
||
rui_user_credential: id BIGINT NOT NULL -- ❌ 缺少 AUTO_INCREMENT
|
||
rui_user_info: id BIGINT NOT NULL -- ❌ 缺少 AUTO_INCREMENT
|
||
rui_user_level: id BIGINT NOT NULL -- ❌ 缺少 AUTO_INCREMENT
|
||
```
|
||
|
||
**专业方案**:
|
||
```
|
||
推荐方案:统一使用 ASSIGN_ID(雪花算法)
|
||
理由:
|
||
1. 分布式环境下自增ID存在冲突风险
|
||
2. 雪花算法ID有序且唯一,适合分库分表
|
||
3. 无需依赖数据库 AUTO_INCREMENT
|
||
4. 支持批量插入时提前知道ID
|
||
|
||
SQL调整:
|
||
- 去掉所有 AUTO_INCREMENT
|
||
- id BIGINT NOT NULL 即可
|
||
- Java实体统一使用 @TableId(type = IdType.ASSIGN_ID)
|
||
```
|
||
|
||
---
|
||
|
||
### 2.4 【严重】BaseEntity 设计缺陷
|
||
|
||
**当前设计**:
|
||
```java
|
||
@Data
|
||
public class BaseEntity implements Serializable {
|
||
private Long id; // ❌ 缺少 @TableId
|
||
private LocalDateTime createdAt; // ❌ 与 SQL created_at 映射
|
||
private LocalDateTime updatedAt; // ❌ 与 SQL updated_at 映射
|
||
private Integer deleted; // ❌ 缺少 @TableLogic
|
||
private Long tenantId; // ❌ 缺少默认值
|
||
}
|
||
```
|
||
|
||
**问题分析**:
|
||
1. **缺少 @TableId**:子类必须重复定义 id + @TableId,违反 DRY 原则
|
||
2. **缺少 @TableLogic**:子类需要手动添加,容易遗漏
|
||
3. **缺少 @TableField(fill = FieldFill.INSERT/UPDATE)**:无法自动填充
|
||
4. **tenantId 无默认值**:SQL 中 DEFAULT 0,但 Java 中为 null,插入时可能报错
|
||
5. **deleted 为 Integer**:MyBatis Plus 的 @TableLogic 推荐配合 Integer,但需要确认数据库 TINYINT 兼容性
|
||
|
||
**专业方案**:
|
||
```java
|
||
@Data
|
||
public class BaseEntity implements Serializable {
|
||
@Serial
|
||
private static final long serialVersionUID = 1L;
|
||
|
||
@TableId(type = IdType.ASSIGN_ID)
|
||
private Long id;
|
||
|
||
@TableField(fill = FieldFill.INSERT)
|
||
private LocalDateTime createdAt;
|
||
|
||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||
private LocalDateTime updatedAt;
|
||
|
||
@TableLogic
|
||
@TableField(fill = FieldFill.INSERT)
|
||
private Integer deleted;
|
||
|
||
@TableField(fill = FieldFill.INSERT)
|
||
private Long tenantId;
|
||
}
|
||
```
|
||
|
||
**SQL 默认值调整**:
|
||
```sql
|
||
-- 统一默认值
|
||
`deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除 0:正常 1:删除',
|
||
`tenant_id` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID 0:系统',
|
||
```
|
||
|
||
---
|
||
|
||
## 三、表结构设计问题
|
||
|
||
### 3.1 数据字典表设计不合理
|
||
|
||
**当前设计(单表)**:
|
||
```sql
|
||
CREATE TABLE rui_system_dict (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
dict_code VARCHAR(100) NOT NULL, -- 字典编码(如:gender, status)
|
||
dict_value VARCHAR(200) NOT NULL, -- 字典值(如:0, 1)
|
||
label VARCHAR(200) NOT NULL, -- 标签(如:男, 女)
|
||
sort_order INT DEFAULT 0,
|
||
status TINYINT DEFAULT 1,
|
||
deleted TINYINT DEFAULT 0,
|
||
...
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. 单表存储所有字典项,数据冗余大
|
||
2. 无法扩展字典属性(如颜色、图标、备注等)
|
||
3. 无法支持树形字典(如地区、部门层级)
|
||
4. 字典编码 dict_code 无索引,查询效率低
|
||
5. 缺少 dict_type(字典类型)表,无法分组管理
|
||
|
||
**专业方案(两表设计)**:
|
||
```sql
|
||
-- 字典类型表
|
||
CREATE TABLE rui_dict_type (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
dict_code VARCHAR(100) NOT NULL COMMENT '字典编码(唯一标识)',
|
||
dict_name VARCHAR(200) NOT NULL COMMENT '字典名称',
|
||
description VARCHAR(500) DEFAULT NULL COMMENT '描述',
|
||
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:禁用 1:启用',
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_dict_code (dict_code),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='字典类型';
|
||
|
||
-- 字典项表
|
||
CREATE TABLE rui_dict_item (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
dict_type_id BIGINT NOT NULL COMMENT '字典类型ID',
|
||
item_code VARCHAR(100) NOT NULL COMMENT '项编码',
|
||
item_label VARCHAR(200) NOT NULL COMMENT '项标签',
|
||
item_value VARCHAR(200) NOT NULL COMMENT '项值',
|
||
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序',
|
||
remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
INDEX idx_dict_type (dict_type_id),
|
||
INDEX idx_tenant (tenant_id),
|
||
UNIQUE KEY uk_dict_type_code (dict_type_id, item_code)
|
||
) COMMENT='字典项';
|
||
```
|
||
|
||
---
|
||
|
||
### 3.2 系统配置表缺少作用域和加密支持
|
||
|
||
**当前设计**:
|
||
```sql
|
||
CREATE TABLE rui_system_config (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
config_key VARCHAR(200) NOT NULL,
|
||
config_value TEXT NOT NULL,
|
||
description VARCHAR(500) DEFAULT NULL,
|
||
deleted TINYINT DEFAULT 0,
|
||
...
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. 缺少 `config_type` 字段,无法区分 STRING/JSON/NUMBER/BOOLEAN/ENCRYPTED
|
||
2. 缺少 `is_system` 字段,无法区分系统级配置和租户级配置
|
||
3. 缺少 `is_encrypted` 字段,敏感配置(如密钥)无法加密存储
|
||
4. `config_value` 用 TEXT 不合理,大部分配置值很短
|
||
5. 缺少 `sort_order`,无法对配置项排序展示
|
||
6. 缺少 `group_code`,无法分组管理(如:oss, sms, email)
|
||
|
||
**专业方案**:
|
||
```sql
|
||
CREATE TABLE rui_config (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
config_group VARCHAR(100) NOT NULL DEFAULT 'default' COMMENT '配置分组(oss/sms/email)',
|
||
config_key VARCHAR(200) NOT NULL COMMENT '配置键',
|
||
config_value VARCHAR(2000) NOT NULL COMMENT '配置值',
|
||
config_type VARCHAR(20) NOT NULL DEFAULT 'STRING' COMMENT '值类型 STRING/JSON/NUMBER/BOOLEAN/ENCRYPTED',
|
||
is_system TINYINT NOT NULL DEFAULT 0 COMMENT '是否系统级 0:租户 1:系统',
|
||
is_encrypted TINYINT NOT NULL DEFAULT 0 COMMENT '是否加密 0:明文 1:密文',
|
||
description VARCHAR(500) DEFAULT NULL,
|
||
sort_order INT NOT NULL DEFAULT 0,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_config_key (tenant_id, config_key),
|
||
INDEX idx_group (config_group),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='系统配置';
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 用户凭证表与用户详情表分离但字段重复
|
||
|
||
**当前设计**:
|
||
```sql
|
||
-- 凭证表
|
||
rui_user_credential: id, username, password, nickname, email, phone, avatar, status
|
||
|
||
-- 详情表
|
||
rui_user_info: id, username, nickname, real_name, email, phone, avatar, gender, birthday, status
|
||
```
|
||
|
||
**问题**:
|
||
1. username/nickname/email/phone/avatar/status 在两张表中重复
|
||
2. 数据一致性难以保证(更新时容易遗漏)
|
||
3. 违背了数据库设计第三范式(3NF)
|
||
|
||
**专业方案(合并为单表 + 扩展表)**:
|
||
```sql
|
||
-- 用户主表(核心字段,登录、认证用)
|
||
CREATE TABLE rui_user (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
username VARCHAR(100) NOT NULL COMMENT '用户名',
|
||
password VARCHAR(255) NOT NULL COMMENT '密码(BCrypt加密)',
|
||
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:禁用 1:启用',
|
||
user_type TINYINT NOT NULL DEFAULT 1 COMMENT '用户类型 1:普通用户 2:管理员 3:系统用户',
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_username (tenant_id, username),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='用户';
|
||
|
||
-- 用户详情表(扩展字段,不经常变更)
|
||
CREATE TABLE rui_user_detail (
|
||
id BIGINT NOT NULL,
|
||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
nickname VARCHAR(100) DEFAULT NULL COMMENT '昵称',
|
||
real_name VARCHAR(100) DEFAULT NULL COMMENT '真实姓名',
|
||
email VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
|
||
phone VARCHAR(20) DEFAULT NULL COMMENT '手机号',
|
||
avatar VARCHAR(500) DEFAULT NULL COMMENT '头像URL',
|
||
gender TINYINT DEFAULT 0 COMMENT '性别 0:未知 1:男 2:女',
|
||
birthday DATE DEFAULT NULL,
|
||
id_card VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
|
||
address VARCHAR(500) DEFAULT NULL COMMENT '地址',
|
||
remark VARCHAR(500) DEFAULT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_user_id (user_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='用户详情';
|
||
```
|
||
|
||
**或者(方案B:保留单表,使用 JSON 扩展字段)**:
|
||
```sql
|
||
CREATE TABLE rui_user (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
username VARCHAR(100) NOT NULL,
|
||
password VARCHAR(255) NOT NULL,
|
||
nickname VARCHAR(100) DEFAULT NULL,
|
||
real_name VARCHAR(100) DEFAULT NULL,
|
||
email VARCHAR(100) DEFAULT NULL,
|
||
phone VARCHAR(20) DEFAULT NULL,
|
||
avatar VARCHAR(500) DEFAULT NULL,
|
||
gender TINYINT DEFAULT 0,
|
||
birthday DATE DEFAULT NULL,
|
||
extra JSON DEFAULT NULL COMMENT '扩展字段(JSON格式)',
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
user_type TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_username (tenant_id, username),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='用户';
|
||
```
|
||
|
||
**推荐方案A**,理由:
|
||
1. 用户主表(rui_user)只保留认证相关字段,查询高效
|
||
2. 详情表(rui_user_detail)按需加载,减少不必要的 JOIN
|
||
3. 符合微服务设计理念:认证服务和用户信息服务可以分离
|
||
4. 支持用户详情的多租户隔离(如不同租户有不同的详情字段)
|
||
|
||
---
|
||
|
||
### 3.4 菜单表缺少关键字段
|
||
|
||
**当前设计**:
|
||
```sql
|
||
CREATE TABLE rui_system_menu (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
parent_id BIGINT DEFAULT 0,
|
||
name VARCHAR(100) NOT NULL,
|
||
permission VARCHAR(200) DEFAULT NULL,
|
||
path VARCHAR(200) DEFAULT NULL,
|
||
component VARCHAR(200) DEFAULT NULL,
|
||
icon VARCHAR(100) DEFAULT NULL,
|
||
sort_order INT DEFAULT 0,
|
||
type TINYINT DEFAULT 0 COMMENT '0:目录 1:菜单 2:按钮',
|
||
visible TINYINT DEFAULT 1,
|
||
status TINYINT DEFAULT 1,
|
||
deleted TINYINT DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
INDEX idx_tenant (tenant_id),
|
||
INDEX idx_parent (parent_id)
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. 缺少 `code` 字段,菜单编码是权限控制的关键标识
|
||
2. 缺少 `target` 字段(_self/_blank),无法控制外链打开方式
|
||
3. 缺少 `keep_alive` 字段,无法控制页面缓存
|
||
4. 缺少 `is_external` 字段,无法区分内部路由和外部链接
|
||
5. 缺少 `description` 字段,菜单说明
|
||
6. `permission` 字段使用 VARCHAR(200),权限标识可能更长
|
||
7. 缺少 `level` 或 `ancestors` 字段,树形查询效率低
|
||
8. `sort_order` 应改为 `sort_no` 或 `sort`,更简洁
|
||
|
||
**专业方案**:
|
||
```sql
|
||
CREATE TABLE rui_menu (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父菜单ID 0:顶级',
|
||
ancestors VARCHAR(500) DEFAULT '' COMMENT '祖级ID列表 如: 0,1,5,',
|
||
menu_code VARCHAR(100) NOT NULL COMMENT '菜单编码(唯一标识)',
|
||
menu_name VARCHAR(100) NOT NULL COMMENT '菜单名称',
|
||
menu_type TINYINT NOT NULL DEFAULT 1 COMMENT '类型 1:目录 2:菜单 3:按钮',
|
||
icon VARCHAR(100) DEFAULT NULL COMMENT '图标',
|
||
path VARCHAR(200) DEFAULT NULL COMMENT '路由路径',
|
||
component VARCHAR(200) DEFAULT NULL COMMENT '组件路径',
|
||
permission VARCHAR(200) DEFAULT NULL COMMENT '权限标识 如: user:list',
|
||
is_external TINYINT NOT NULL DEFAULT 0 COMMENT '是否外链 0:否 1:是',
|
||
target VARCHAR(20) DEFAULT '_self' COMMENT '打开方式 _self/_blank',
|
||
keep_alive TINYINT NOT NULL DEFAULT 0 COMMENT '是否缓存 0:否 1:是',
|
||
visible TINYINT NOT NULL DEFAULT 1 COMMENT '是否显示 0:隐藏 1:显示',
|
||
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:禁用 1:启用',
|
||
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序号',
|
||
remark VARCHAR(500) DEFAULT NULL,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_menu_code (tenant_id, menu_code),
|
||
INDEX idx_parent (parent_id),
|
||
INDEX idx_ancestors (ancestors(100)),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='菜单';
|
||
```
|
||
|
||
---
|
||
|
||
### 3.5 角色表设计不完善
|
||
|
||
**当前设计**:
|
||
```sql
|
||
CREATE TABLE rui_system_role (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
parent_id BIGINT DEFAULT 0 COMMENT '上级角色',
|
||
name VARCHAR(100) NOT NULL,
|
||
code VARCHAR(100) NOT NULL,
|
||
description VARCHAR(500) DEFAULT NULL,
|
||
status TINYINT DEFAULT 1,
|
||
deleted TINYINT DEFAULT 0,
|
||
...
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. 缺少 `role_type` 字段(系统角色/租户角色/自定义角色)
|
||
2. 缺少 `data_scope` 字段(数据权限范围:全部/本部门/本部门及子部门/仅本人/自定义)
|
||
3. `parent_id` 实现角色层级,但没有 `ancestors` 字段,查询效率低
|
||
4. 缺少 `sort_no` 字段,无法排序
|
||
5. `code` 字段应加租户级唯一索引
|
||
|
||
**专业方案**:
|
||
```sql
|
||
CREATE TABLE rui_role (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
parent_id BIGINT NOT NULL DEFAULT 0,
|
||
ancestors VARCHAR(500) DEFAULT '' COMMENT '祖级ID列表',
|
||
role_code VARCHAR(100) NOT NULL COMMENT '角色编码',
|
||
role_name VARCHAR(100) NOT NULL COMMENT '角色名称',
|
||
role_type TINYINT NOT NULL DEFAULT 1 COMMENT '类型 1:系统角色 2:租户角色 3:自定义',
|
||
data_scope TINYINT NOT NULL DEFAULT 1 COMMENT '数据范围 1:全部 2:本部门 3:本部门及子部门 4:仅本人 5:自定义',
|
||
description VARCHAR(500) DEFAULT NULL,
|
||
sort_no INT NOT NULL DEFAULT 0,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_role_code (tenant_id, role_code),
|
||
INDEX idx_parent (parent_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='角色';
|
||
```
|
||
|
||
---
|
||
|
||
### 3.6 关联表设计不规范
|
||
|
||
**当前设计**:
|
||
```sql
|
||
-- 用户角色关联
|
||
CREATE TABLE rui_user_role (
|
||
user_id BIGINT NOT NULL,
|
||
role_id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
PRIMARY KEY (user_id, role_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
);
|
||
|
||
-- 角色菜单关联
|
||
CREATE TABLE rui_system_role_menu (
|
||
role_id BIGINT NOT NULL,
|
||
menu_id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
PRIMARY KEY (role_id, menu_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
);
|
||
```
|
||
|
||
**问题**:
|
||
1. 没有自增 ID,不利于后续扩展(如增加有效期、创建人等字段)
|
||
2. 缺少 `created_at` 字段,无法追踪关联建立时间
|
||
3. 缺少单独的索引用于反向查询(如根据 role_id 查所有 user)
|
||
4. 表名应统一为 `rui_user_role` 和 `rui_role_menu`(去掉 system 模块前缀)
|
||
|
||
**专业方案**:
|
||
```sql
|
||
-- 用户角色关联
|
||
CREATE TABLE rui_user_role (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
user_id BIGINT NOT NULL,
|
||
role_id BIGINT NOT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_user_role (tenant_id, user_id, role_id),
|
||
INDEX idx_user (user_id),
|
||
INDEX idx_role (role_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='用户角色关联';
|
||
|
||
-- 角色菜单关联
|
||
CREATE TABLE rui_role_menu (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
role_id BIGINT NOT NULL,
|
||
menu_id BIGINT NOT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_role_menu (tenant_id, role_id, menu_id),
|
||
INDEX idx_role (role_id),
|
||
INDEX idx_menu (menu_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='角色菜单关联';
|
||
```
|
||
|
||
---
|
||
|
||
### 3.7 等级表缺少业务关联
|
||
|
||
**当前设计**:
|
||
```sql
|
||
CREATE TABLE rui_user_level (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
name VARCHAR(100) NOT NULL,
|
||
code VARCHAR(100) NOT NULL,
|
||
min_score INT DEFAULT 0,
|
||
max_score INT DEFAULT 0,
|
||
icon VARCHAR(500) DEFAULT NULL,
|
||
benefits JSON DEFAULT NULL,
|
||
status TINYINT DEFAULT 1,
|
||
deleted TINYINT DEFAULT 0,
|
||
...
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. `min_score`/`max_score` 设计不合理,等级晋升应该是累计积分达到阈值
|
||
2. 缺少 `level` 字段(数字等级,如 1, 2, 3...),用于快速比较等级高低
|
||
3. `benefits` 用 JSON 是好的,但缺少 `benefits_type` 字段说明权益类型
|
||
4. 缺少 `upgrade_type` 字段(自动升级/手动审核)
|
||
5. 缺少 `expire_days` 字段,等级有效期
|
||
|
||
**专业方案**:
|
||
```sql
|
||
CREATE TABLE rui_user_level (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
level_code VARCHAR(100) NOT NULL COMMENT '等级编码',
|
||
level_name VARCHAR(100) NOT NULL COMMENT '等级名称',
|
||
level_no INT NOT NULL DEFAULT 1 COMMENT '等级序号(数字越大等级越高)',
|
||
min_score INT NOT NULL DEFAULT 0 COMMENT '最低积分要求',
|
||
icon VARCHAR(500) DEFAULT NULL COMMENT '等级图标',
|
||
benefits JSON DEFAULT NULL COMMENT '权益配置(JSON)',
|
||
upgrade_type TINYINT NOT NULL DEFAULT 1 COMMENT '升级方式 1:自动 2:手动审核',
|
||
expire_days INT DEFAULT 0 COMMENT '有效期(天) 0:永久',
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
sort_no INT NOT NULL DEFAULT 0,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_level_code (tenant_id, level_code),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='用户等级';
|
||
```
|
||
|
||
---
|
||
|
||
### 3.8 等级日志表设计不足
|
||
|
||
**当前设计**:
|
||
```sql
|
||
CREATE TABLE rui_user_level_log (
|
||
id BIGINT NOT NULL,
|
||
user_id BIGINT NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
from_level_id BIGINT DEFAULT NULL,
|
||
to_level_id BIGINT NOT NULL,
|
||
reason VARCHAR(500) DEFAULT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
...
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. 缺少 `change_type` 字段(升级/降级/手动调整/过期)
|
||
2. 缺少 `operator_id` 字段,无法追踪操作人
|
||
3. 缺少 `operator_type` 字段(系统/管理员/用户)
|
||
4. `from_level_id` 为 NULL 时无法表达"初始等级"
|
||
5. 缺少 `score_change` 字段,记录积分变化
|
||
|
||
**专业方案**:
|
||
```sql
|
||
CREATE TABLE rui_user_level_log (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
user_id BIGINT NOT NULL COMMENT '用户ID',
|
||
change_type TINYINT NOT NULL DEFAULT 1 COMMENT '变更类型 1:升级 2:降级 3:手动调整 4:过期',
|
||
from_level_id BIGINT DEFAULT NULL COMMENT '原等级ID NULL:初始',
|
||
to_level_id BIGINT NOT NULL COMMENT '新等级ID',
|
||
score_before INT DEFAULT NULL COMMENT '变更前积分',
|
||
score_after INT DEFAULT NULL COMMENT '变更后积分',
|
||
reason VARCHAR(500) DEFAULT NULL COMMENT '变更原因',
|
||
operator_id BIGINT DEFAULT NULL COMMENT '操作人ID',
|
||
operator_type TINYINT NOT NULL DEFAULT 1 COMMENT '操作人类型 1:系统 2:管理员 3:用户',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
INDEX idx_user (user_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='用户等级变更记录';
|
||
```
|
||
|
||
---
|
||
|
||
### 3.9 OAuth2 客户端表字段过长且缺少索引
|
||
|
||
**当前设计**:
|
||
```sql
|
||
CREATE TABLE rui_system_oauth2_client (
|
||
id VARCHAR(100) NOT NULL,
|
||
tenant_id BIGINT DEFAULT 0,
|
||
client_id VARCHAR(100) NOT NULL,
|
||
client_id_issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||
client_secret VARCHAR(200) DEFAULT NULL,
|
||
client_secret_expires_at TIMESTAMP DEFAULT NULL,
|
||
client_name VARCHAR(200) NOT NULL,
|
||
client_authentication_methods VARCHAR(1000) NOT NULL, -- ❌ 过长
|
||
authorization_grant_types VARCHAR(1000) NOT NULL, -- ❌ 过长
|
||
redirect_uris VARCHAR(1000) DEFAULT NULL, -- ❌ 过长
|
||
post_logout_redirect_uris VARCHAR(1000) DEFAULT NULL, -- ❌ 过长
|
||
scopes VARCHAR(1000) NOT NULL, -- ❌ 过长
|
||
client_settings VARCHAR(2000) NOT NULL, -- ❌ 过长
|
||
token_settings VARCHAR(2000) NOT NULL, -- ❌ 过长
|
||
PRIMARY KEY (id),
|
||
INDEX idx_tenant (tenant_id)
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. 多个 VARCHAR(1000/2000) 字段不合理,应使用 TEXT
|
||
2. 缺少 `client_id` 的唯一索引
|
||
3. `id` 使用 VARCHAR(100),不如使用 BIGINT + ASSIGN_ID
|
||
4. 缺少 `status` 字段,无法禁用客户端
|
||
5. 缺少 `description` 字段
|
||
6. 时间字段使用 TIMESTAMP,不如使用 DATETIME
|
||
|
||
**专业方案**:
|
||
```sql
|
||
CREATE TABLE rui_oauth2_client (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
client_id VARCHAR(100) NOT NULL COMMENT '客户端ID',
|
||
client_secret VARCHAR(255) DEFAULT NULL COMMENT '客户端密钥',
|
||
client_name VARCHAR(200) NOT NULL COMMENT '客户端名称',
|
||
client_type TINYINT NOT NULL DEFAULT 1 COMMENT '客户端类型 1:Web 2:App 3:小程序',
|
||
logo_url VARCHAR(500) DEFAULT NULL COMMENT 'Logo',
|
||
description VARCHAR(500) DEFAULT NULL,
|
||
authentication_methods VARCHAR(500) NOT NULL COMMENT '认证方式',
|
||
grant_types VARCHAR(500) NOT NULL COMMENT '授权类型',
|
||
redirect_uris TEXT DEFAULT NULL COMMENT '回调地址(逗号分隔)',
|
||
scopes VARCHAR(500) NOT NULL COMMENT '授权范围',
|
||
access_token_ttl INT NOT NULL DEFAULT 7200 COMMENT '访问令牌有效期(秒)',
|
||
refresh_token_ttl INT NOT NULL DEFAULT 604800 COMMENT '刷新令牌有效期(秒)',
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_client_id (tenant_id, client_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='OAuth2客户端';
|
||
```
|
||
|
||
**说明**:
|
||
- `client_settings` 和 `token_settings` 不建议用 JSON/VARCHAR 存储,应在代码中配置模板
|
||
- `redirect_uris` 使用 TEXT,因为可能有多个URL
|
||
- `client_id_issued_at`/`client_secret_expires_at` 去掉,实际业务中很少用到
|
||
- `post_logout_redirect_uris` 去掉,OAuth2 退出回调通常不需要配置
|
||
|
||
---
|
||
|
||
### 3.10 租户表缺少关键字段
|
||
|
||
**当前设计**:
|
||
```sql
|
||
CREATE TABLE rui_system_tenant (
|
||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||
tenant_code VARCHAR(50) NOT NULL COMMENT '租户编码',
|
||
tenant_name VARCHAR(200) NOT NULL COMMENT '租户名称',
|
||
contact_name VARCHAR(100) DEFAULT NULL,
|
||
contact_phone VARCHAR(20) DEFAULT NULL,
|
||
contact_email VARCHAR(100) DEFAULT NULL,
|
||
domain VARCHAR(200) DEFAULT NULL,
|
||
status TINYINT DEFAULT 1,
|
||
deleted TINYINT DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_tenant_code (tenant_code)
|
||
)
|
||
```
|
||
|
||
**问题**:
|
||
1. 缺少 `tenant_type` 字段(企业/个人/试用)
|
||
2. 缺少 `expire_time` 字段,租户有效期
|
||
3. 缺少 `max_user_count` 字段,最大用户数限制
|
||
4. 缺少 `logo` 字段,租户 Logo
|
||
5. 缺少 `package_id` 字段,关联套餐/版本
|
||
6. `domain` 应支持多个域名(用逗号分隔或单独表)
|
||
7. 缺少 `super_admin_id` 字段,记录租户创建人/超管
|
||
|
||
**专业方案**:
|
||
```sql
|
||
CREATE TABLE rui_tenant (
|
||
id BIGINT NOT NULL,
|
||
tenant_code VARCHAR(50) NOT NULL COMMENT '租户编码',
|
||
tenant_name VARCHAR(200) NOT NULL COMMENT '租户名称',
|
||
tenant_type TINYINT NOT NULL DEFAULT 1 COMMENT '类型 1:企业 2:个人 3:试用',
|
||
tenant_level TINYINT NOT NULL DEFAULT 1 COMMENT '等级 1:基础版 2:专业版 3:旗舰版',
|
||
logo_url VARCHAR(500) DEFAULT NULL COMMENT 'Logo',
|
||
contact_name VARCHAR(100) DEFAULT NULL,
|
||
contact_phone VARCHAR(20) DEFAULT NULL,
|
||
contact_email VARCHAR(100) DEFAULT NULL,
|
||
domains VARCHAR(500) DEFAULT NULL COMMENT '绑定域名(逗号分隔)',
|
||
max_user_count INT NOT NULL DEFAULT 100 COMMENT '最大用户数',
|
||
expire_time DATETIME DEFAULT NULL COMMENT '过期时间 NULL:永久',
|
||
super_admin_id BIGINT DEFAULT NULL COMMENT '超管用户ID',
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_tenant_code (tenant_code),
|
||
INDEX idx_status (status)
|
||
) COMMENT='租户';
|
||
```
|
||
|
||
---
|
||
|
||
## 四、缺少的关键表
|
||
|
||
### 4.1 操作日志表
|
||
|
||
**必要性**:审计、追踪、安全
|
||
|
||
```sql
|
||
CREATE TABLE rui_oper_log (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
oper_type TINYINT NOT NULL DEFAULT 1 COMMENT '操作类型 1:新增 2:修改 3:删除 4:查询 5:导出 6:登录 7:登出',
|
||
title VARCHAR(200) NOT NULL COMMENT '操作模块',
|
||
method VARCHAR(500) DEFAULT NULL COMMENT '请求方法',
|
||
request_url VARCHAR(500) DEFAULT NULL COMMENT '请求URL',
|
||
request_method VARCHAR(10) DEFAULT NULL COMMENT '请求方式 GET/POST/PUT/DELETE',
|
||
request_params TEXT DEFAULT NULL COMMENT '请求参数',
|
||
response_data TEXT DEFAULT NULL COMMENT '响应数据',
|
||
user_id BIGINT DEFAULT NULL COMMENT '操作用户ID',
|
||
user_name VARCHAR(100) DEFAULT NULL COMMENT '操作用户名',
|
||
oper_ip VARCHAR(128) DEFAULT NULL COMMENT '操作IP',
|
||
oper_location VARCHAR(255) DEFAULT NULL COMMENT '操作地点',
|
||
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功',
|
||
error_msg TEXT DEFAULT NULL COMMENT '错误消息',
|
||
cost_time BIGINT DEFAULT 0 COMMENT '耗时(ms)',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
INDEX idx_user (user_id),
|
||
INDEX idx_tenant (tenant_id),
|
||
INDEX idx_created (created_at)
|
||
) COMMENT='操作日志';
|
||
```
|
||
|
||
### 4.2 登录日志表
|
||
|
||
**必要性**:安全审计、异常登录检测
|
||
|
||
```sql
|
||
CREATE TABLE rui_login_log (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
user_id BIGINT DEFAULT NULL,
|
||
username VARCHAR(100) DEFAULT NULL,
|
||
login_type TINYINT NOT NULL DEFAULT 1 COMMENT '登录类型 1:密码 2:短信 3:微信 4:支付宝',
|
||
client_id VARCHAR(100) DEFAULT NULL COMMENT '客户端ID',
|
||
ip VARCHAR(128) DEFAULT NULL,
|
||
location VARCHAR(255) DEFAULT NULL,
|
||
browser VARCHAR(200) DEFAULT NULL,
|
||
os VARCHAR(200) DEFAULT NULL,
|
||
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0:失败 1:成功',
|
||
msg VARCHAR(500) DEFAULT NULL COMMENT '消息',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
INDEX idx_user (user_id),
|
||
INDEX idx_tenant (tenant_id),
|
||
INDEX idx_created (created_at)
|
||
) COMMENT='登录日志';
|
||
```
|
||
|
||
### 4.3 部门/组织表
|
||
|
||
**必要性**:组织架构、数据权限
|
||
|
||
```sql
|
||
CREATE TABLE rui_dept (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
parent_id BIGINT NOT NULL DEFAULT 0,
|
||
ancestors VARCHAR(500) DEFAULT '' COMMENT '祖级ID列表',
|
||
dept_code VARCHAR(100) NOT NULL COMMENT '部门编码',
|
||
dept_name VARCHAR(100) NOT NULL COMMENT '部门名称',
|
||
leader_id BIGINT DEFAULT NULL COMMENT '负责人ID',
|
||
phone VARCHAR(20) DEFAULT NULL,
|
||
email VARCHAR(100) DEFAULT NULL,
|
||
sort_no INT NOT NULL DEFAULT 0,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_dept_code (tenant_id, dept_code),
|
||
INDEX idx_parent (parent_id),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='部门';
|
||
|
||
-- 用户部门关联表
|
||
CREATE TABLE rui_user_dept (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
user_id BIGINT NOT NULL,
|
||
dept_id BIGINT NOT NULL,
|
||
is_main TINYINT NOT NULL DEFAULT 1 COMMENT '是否主部门 0:否 1:是',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_user_dept (tenant_id, user_id, dept_id),
|
||
INDEX idx_user (user_id),
|
||
INDEX idx_dept (dept_id)
|
||
) COMMENT='用户部门关联';
|
||
```
|
||
|
||
### 4.4 岗位表
|
||
|
||
**必要性**:职位体系、审批流
|
||
|
||
```sql
|
||
CREATE TABLE rui_post (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
post_code VARCHAR(100) NOT NULL COMMENT '岗位编码',
|
||
post_name VARCHAR(100) NOT NULL COMMENT '岗位名称',
|
||
sort_no INT NOT NULL DEFAULT 0,
|
||
status TINYINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_post_code (tenant_id, post_code),
|
||
INDEX idx_tenant (tenant_id)
|
||
) COMMENT='岗位';
|
||
|
||
-- 用户岗位关联表
|
||
CREATE TABLE rui_user_post (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
user_id BIGINT NOT NULL,
|
||
post_id BIGINT NOT NULL,
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_user_post (tenant_id, user_id, post_id),
|
||
INDEX idx_user (user_id)
|
||
) COMMENT='用户岗位关联';
|
||
```
|
||
|
||
### 4.5 用户权限直接关联表(可选)
|
||
|
||
**必要性**:支持用户直接拥有权限(不通过角色)
|
||
|
||
```sql
|
||
CREATE TABLE rui_user_permission (
|
||
id BIGINT NOT NULL,
|
||
tenant_id BIGINT NOT NULL DEFAULT 0,
|
||
user_id BIGINT NOT NULL,
|
||
permission VARCHAR(200) NOT NULL COMMENT '权限标识',
|
||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_user_permission (tenant_id, user_id, permission),
|
||
INDEX idx_user (user_id)
|
||
) COMMENT='用户权限关联(直接授权)';
|
||
```
|
||
|
||
---
|
||
|
||
## 五、索引设计问题
|
||
|
||
### 5.1 当前索引缺陷
|
||
|
||
| 表名 | 当前索引 | 问题 |
|
||
|------|---------|------|
|
||
| rui_user_credential | uk_username | 未包含 tenant_id,多租户下会冲突 |
|
||
| rui_user_info | idx_username | 未加唯一约束,用户名可重复 |
|
||
| rui_system_role | uk_code | 未包含 tenant_id,多租户下会冲突 |
|
||
| rui_system_config | uk_config_key | 未包含 tenant_id,多租户下会冲突 |
|
||
| rui_user_role | PRIMARY (user_id, role_id) | 缺少反向索引(根据 role_id 查 user) |
|
||
|
||
### 5.2 索引设计原则
|
||
|
||
```
|
||
1. 所有唯一索引必须包含 tenant_id(多租户环境)
|
||
错误: UNIQUE KEY uk_code (code)
|
||
正确: UNIQUE KEY uk_code (tenant_id, code)
|
||
|
||
2. 外键关联表必须建双向索引
|
||
错误: 只有 PRIMARY KEY (user_id, role_id)
|
||
正确: + INDEX idx_role (role_id)
|
||
|
||
3. 时间字段建索引用于分页查询
|
||
INDEX idx_created (created_at)
|
||
|
||
4. 状态字段建索引用于筛选
|
||
INDEX idx_status (status)
|
||
|
||
5. 组合索引遵循最左前缀原则
|
||
正确: INDEX idx_tenant_status (tenant_id, status)
|
||
错误: INDEX idx_status_tenant (status, tenant_id) -- status 区分度低
|
||
```
|
||
|
||
---
|
||
|
||
## 六、字段命名规范问题
|
||
|
||
### 6.1 当前不一致之处
|
||
|
||
| 位置 | 命名方式 | 示例 |
|
||
|------|---------|------|
|
||
| SQL | 下划线命名 | created_at, updated_at |
|
||
| Java BaseEntity | 驼峰命名 | createdAt, updatedAt |
|
||
| Java 部分实体 | 驼峰命名 | realName, tenantCode |
|
||
| 表名 | rui_前缀 + 模块_表名 | rui_system_tenant |
|
||
| 实体 @TableName | 无 rui_前缀 + 不一致前缀 | auth_tenant, user_info |
|
||
|
||
### 6.2 推荐规范
|
||
|
||
```
|
||
SQL 层:
|
||
- 表名: 小写下划线,项目前缀 + 表名(如: rui_user, rui_menu)
|
||
- 字段名: 小写下划线(如: user_name, created_at)
|
||
- 索引名: uk_字段名 / idx_字段名
|
||
|
||
Java 层:
|
||
- 类名: 大驼峰(如: User, Menu)
|
||
- 属性名: 小驼峰(如: userName, createdAt)
|
||
- @TableName: 不包含前缀(如: "user", "menu")
|
||
- keepGlobalPrefix: true(自动加 rui_ 前缀)
|
||
```
|
||
|
||
---
|
||
|
||
## 七、时间字段设计
|
||
|
||
### 7.1 当前问题
|
||
|
||
- 使用 DATETIME 类型(无精度)
|
||
- 无统一命名规范
|
||
- 部分表缺少 updated_at
|
||
|
||
### 7.2 专业方案
|
||
|
||
```sql
|
||
-- 推荐: DATETIME(3) 支持毫秒精度
|
||
-- 或: TIMESTAMP(3) 支持毫秒且自动时区转换
|
||
|
||
-- 统一时间字段
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
|
||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
|
||
|
||
-- 如果需要删除时间(用于回收站功能)
|
||
`deleted_at` DATETIME(3) DEFAULT NULL COMMENT '删除时间',
|
||
```
|
||
|
||
**注意**:
|
||
- 使用 `DATETIME(3)` 而非 `TIMESTAMP`,因为 TIMESTAMP 有 2038 年问题
|
||
- MySQL 5.6.4+ 支持小数秒精度
|
||
- Java 对应 `LocalDateTime`,JDBC 自动处理精度
|
||
|
||
---
|
||
|
||
## 八、数据类型规范
|
||
|
||
### 8.1 当前问题
|
||
|
||
| 字段 | 当前类型 | 问题 |
|
||
|------|---------|------|
|
||
| status | TINYINT | 合理,但建议 NOT NULL DEFAULT 1 |
|
||
| deleted | TINYINT | 合理,但建议 NOT NULL DEFAULT 0 |
|
||
| tenant_id | BIGINT DEFAULT 0 | 建议 NOT NULL DEFAULT 0 |
|
||
| avatar | VARCHAR(500) | URL 长度可能不够,建议 VARCHAR(1000) |
|
||
| password | VARCHAR(500) | BCrypt 密码固定 60 字符,VARCHAR(255) 足够 |
|
||
| id | BIGINT NOT NULL | 建议统一,部分表缺少 AUTO_INCREMENT 或主键策略 |
|
||
| JSON 字段 | JSON | 使用正确,但需确认 MySQL 版本支持 |
|
||
|
||
### 8.2 推荐类型映射
|
||
|
||
| 业务类型 | MySQL 类型 | Java 类型 | 说明 |
|
||
|---------|-----------|----------|------|
|
||
| 主键 | BIGINT | Long | 雪花算法生成 |
|
||
| 状态/枚举 | TINYINT NOT NULL DEFAULT x | Integer | 0:禁用 1:启用 |
|
||
| 租户ID | BIGINT NOT NULL DEFAULT 0 | Long | 0:系统 |
|
||
| 字符串(短) | VARCHAR(50-200) | String | 用户名、编码 |
|
||
| 字符串(中) | VARCHAR(500) | String | 名称、标题 |
|
||
| 字符串(长) | VARCHAR(2000) | String | 描述、备注 |
|
||
| 文本 | TEXT | String | 内容、日志 |
|
||
| JSON | JSON | String/Object | 配置、扩展字段 |
|
||
| 金额 | DECIMAL(19,4) | BigDecimal | 精确计算 |
|
||
| 时间 | DATETIME(3) | LocalDateTime | 毫秒精度 |
|
||
| 日期 | DATE | LocalDate | 生日、有效期 |
|
||
| IP | VARCHAR(128) | String | IPv6 兼容 |
|
||
| URL | VARCHAR(1000) | String | 头像、链接 |
|
||
|
||
---
|
||
|
||
## 九、总结:核心问题清单
|
||
|
||
### 🔴 致命问题(必须修改)
|
||
|
||
1. **实体类表名与 SQL 表名不一致**(SystemOAuth2Client, SystemTenant, UserCredential)
|
||
2. **BaseEntity 缺少关键注解**(@TableId, @TableLogic, @TableField)
|
||
3. **主键策略不统一**(ASSIGN_ID vs AUTO)
|
||
4. **6 张表缺少实体类**(user_role, system_menu, system_role, system_role_menu, system_dict, system_config)
|
||
5. **关联表缺少自增 ID**(user_role, role_menu)
|
||
|
||
### 🟡 严重问题(建议修改)
|
||
|
||
6. 字典表应拆分为 dict_type + dict_item
|
||
7. 用户凭证表与用户详情表字段重复,应合并或拆分
|
||
8. 系统配置表缺少作用域、加密、分组支持
|
||
9. 菜单表缺少 code、target、keep_alive 等关键字段
|
||
10. 角色表缺少 data_scope、role_type 字段
|
||
11. OAuth2 客户端表字段过长,应优化
|
||
12. 租户表缺少 tenant_type、expire_time、max_user_count 字段
|
||
13. 等级表设计不合理(min_score/max_score)
|
||
|
||
### 🟢 优化问题(可选修改)
|
||
|
||
14. 缺少操作日志表、登录日志表
|
||
15. 缺少部门表、岗位表
|
||
16. 索引未包含 tenant_id(多租户冲突)
|
||
17. 时间字段未使用 DATETIME(3) 精度
|
||
18. 字段命名未完全统一
|
||
|
||
---
|
||
|
||
## 十、推荐的数据库设计规范(新增规则)
|
||
|
||
```markdown
|
||
## 数据库设计规范
|
||
|
||
### 命名规范
|
||
1. 表名: `rui_` + 业务表名(小写下划线),如: `rui_user`, `rui_menu`
|
||
2. 字段名: 小写下划线,如: `user_name`, `created_at`
|
||
3. 索引名: `uk_字段名`(唯一), `idx_字段名`(普通)
|
||
4. 实体类名: 大驼峰,如: `User`, `Menu`
|
||
5. 实体属性: 小驼峰,如: `userName`, `createdAt`
|
||
6. @TableName: 不包含 `rui_` 前缀,如: `"user"`, `"menu"`
|
||
|
||
### 字段规范
|
||
1. 每张表必须包含: id, tenant_id, deleted, created_at, updated_at
|
||
2. id: BIGINT, 统一使用雪花算法(@TableId(type = IdType.ASSIGN_ID))
|
||
3. tenant_id: BIGINT NOT NULL DEFAULT 0, 0 表示系统级
|
||
4. deleted: TINYINT NOT NULL DEFAULT 0, 逻辑删除标志
|
||
5. created_at: DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
|
||
6. updated_at: DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)
|
||
7. status: TINYINT NOT NULL DEFAULT 1, 0:禁用 1:启用
|
||
|
||
### 索引规范
|
||
1. 主键: 单列 BIGINT,雪花算法生成
|
||
2. 唯一索引: 必须包含 tenant_id,如: `UNIQUE KEY uk_code (tenant_id, code)`
|
||
3. 外键关联表: 建双向索引(如 user_role 表需 idx_user 和 idx_role)
|
||
4. 时间字段: 建索引支持分页查询
|
||
5. 状态字段: 建索引支持筛选
|
||
|
||
### 关联表规范
|
||
1. 必须包含自增 ID(雪花算法)
|
||
2. 必须包含 tenant_id
|
||
3. 必须包含 created_at
|
||
4. 联合字段建唯一索引: `UNIQUE KEY uk_rel (tenant_id, from_id, to_id)`
|
||
|
||
### 数据类型规范
|
||
1. 状态/枚举: TINYINT NOT NULL DEFAULT x
|
||
2. 字符串(短): VARCHAR(50-200)
|
||
3. 字符串(中): VARCHAR(500)
|
||
4. 字符串(长): VARCHAR(2000)
|
||
5. 文本内容: TEXT
|
||
6. JSON: JSON 类型(MySQL 5.7+)
|
||
7. 金额: DECIMAL(19,4)
|
||
8. 时间: DATETIME(3)
|
||
9. URL: VARCHAR(1000)
|
||
|
||
### 多租户规范
|
||
1. 所有业务表必须包含 tenant_id 字段
|
||
2. 系统级表(如字典类型)可不含 tenant_id
|
||
3. 租户过滤使用 MyBatis Plus TenantLineInnerInterceptor
|
||
4. 系统租户(ID=1)对某些表有特权访问
|
||
```
|
||
|
||
---
|
||
|
||
> **文档版本**: v1.0
|
||
> **分析日期**: 2026-05-28
|
||
> **分析范围**: init-database.sql + 所有 Entity 实体类
|
||
> **状态**: 仅分析,未实施任何修改
|