415 lines
15 KiB
Markdown
415 lines
15 KiB
Markdown
# 4.9 数据库设计
|
||
|
||
:::tip 概述
|
||
项目支持 MySQL、PostgreSQL、SQL Server、Oracle、SQLite 五种数据库,通过 `.env` 的 `DB_CONNECTION` 一键切换,`document/` 下提供五套初始化脚本。所有数据库共用同一套代码,无需修改业务逻辑。本章涵盖命名规范、表结构设计、字段说明、索引策略和多数据库适配。
|
||
:::
|
||
|
||
## 命名规范
|
||
|
||
| 对象 | 规范 | 示例 |
|
||
|------|------|------|
|
||
| 表名 | 不含前缀的业务名 + `DB_PREFIX`(默认 `laravel_`) | `laravel_user`、`laravel_article` |
|
||
| 模型 `$table` | **不含前缀** | `protected $table = 'user'` |
|
||
| 字段名 | 小写下划线 | `create_time`、`user_name` |
|
||
| 主键 | 统一 `id`,INT 自增 | `id INT PRIMARY KEY` |
|
||
| 外键 | `表名_id` | `user_id`、`role_id` |
|
||
| 索引 | `idx_字段名` | `idx_status`、`idx_tenant_id` |
|
||
| 唯一索引 | `uk_含义`(常含 `is_delete` 协同) | `uk_tenant_username` |
|
||
|
||
## 公共字段
|
||
|
||
所有业务表**必须**包含以下公共字段,由模型 Trait 自动维护:
|
||
|
||
```sql
|
||
-- MySQL 格式
|
||
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
|
||
is_delete TINYINT(1) DEFAULT 0 COMMENT '软删除 0=正常 1=已删除',
|
||
create_user VARCHAR(50) DEFAULT '' COMMENT '创建人',
|
||
create_time DATETIME COMMENT '创建时间',
|
||
update_user VARCHAR(50) DEFAULT '' COMMENT '更新人',
|
||
update_time DATETIME COMMENT '更新时间'
|
||
```
|
||
|
||
| 字段 | 自动维护方 | 说明 |
|
||
|------|-----------|------|
|
||
| `is_delete` | `SoftDeletesByFlag` | `softDelete()` 设置为 1,`SoftDeleteFlagScope` 全局过滤 |
|
||
| `create_user` | `HasAuditColumns` creating 事件 | 取 `Auth::username()`,已传入则不覆盖 |
|
||
| `create_time` | `HasAuditColumns` creating 事件 | 取 `now()`,已传入则不覆盖 |
|
||
| `update_user` | `HasAuditColumns` updating 事件 | 取 `Auth::username()` |
|
||
| `update_time` | `HasAuditColumns` updating 事件 | 始终覆盖为当前时间 |
|
||
|
||
## 核心表清单(25 张)
|
||
|
||
### 用户与权限(5 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_user` | 用户表 | `BaseTenantService` |
|
||
| `laravel_user_role` | 用户角色关联表(N:N 中间表) | — |
|
||
| `laravel_role` | 角色表 | `BaseTenantService` |
|
||
| `laravel_role_menu` | 角色菜单关联表(N:N 中间表) | — |
|
||
| `laravel_menu` | 菜单/权限表(菜单即权限) | `BaseService` |
|
||
|
||
**关联关系:**
|
||
|
||
```text
|
||
laravel_user ──┐
|
||
│ N:N (laravel_user_role)
|
||
laravel_role ──┤
|
||
│ N:N (laravel_role_menu)
|
||
laravel_menu ──┘
|
||
|
||
laravel_dept ←── laravel_user.dept_id
|
||
laravel_tenant ←── laravel_user.tenant_id
|
||
```
|
||
|
||
### 组织架构(3 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_dept` | 部门表(树形,parent_id) | `BaseTenantService` |
|
||
| `laravel_position` | 岗位表 | `BaseTenantService` |
|
||
| `laravel_level` | 职级表 | `BaseTenantService` |
|
||
|
||
### 租户(1 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_tenant` | 租户表(状态、过期时间、用户数限制) | `BaseService` |
|
||
|
||
### 系统配置(5 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_dict` | 字典表 | `BaseService` |
|
||
| `laravel_dict_item` | 字典项表 | `BaseService` |
|
||
| `laravel_config` | 配置组表 | `BaseService` |
|
||
| `laravel_config_item` | 配置项表 | `BaseService` |
|
||
| `laravel_param` | 系统参数表 | `BaseService` |
|
||
|
||
**关联关系:**
|
||
|
||
```text
|
||
laravel_dict ←── laravel_dict_item.dict_id
|
||
laravel_config ←── laravel_config_item.config_id
|
||
```
|
||
|
||
### 内容管理(4 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_article` | 文章表 | `BaseTenantService` |
|
||
| `laravel_category` | 文章分类表(树形) | `BaseTenantService` |
|
||
| `laravel_link` | 友情链接表 | `BaseTenantService` |
|
||
| `laravel_notice` | 通知公告表 | `BaseTenantService` |
|
||
|
||
### 日志审计(2 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_login_log` | 登录日志表 | `BaseService` |
|
||
| `laravel_operation_log` | 操作日志表 | `BaseService` |
|
||
|
||
### 定时任务(2 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_job` | 定时任务表 | `BaseService` |
|
||
| `laravel_job_log` | 定时任务执行日志表 | `BaseService` |
|
||
|
||
**关联关系:**
|
||
|
||
```text
|
||
laravel_job ←── laravel_job_log.job_id
|
||
```
|
||
|
||
### 基础数据(3 张)
|
||
|
||
| 表名 | 说明 | Service 基类 |
|
||
|------|------|-----------|
|
||
| `laravel_city` | 城市行政区划表(树形) | `BaseService` |
|
||
| `laravel_file_template` | 文件模板表 | `BaseService` |
|
||
| `laravel_example` | 案例演示表(生成器参考模板) | `BaseService` |
|
||
|
||
:::tip 租户隔离范围
|
||
继承 `BaseTenantService` 的 9 个服务:User / Role / Dept / Position / Level / Article / Category / Notice / Link——业务数据按租户隔离;系统共享数据(字典、配置、菜单、日志等)继承 `BaseService` 不隔离。
|
||
:::
|
||
|
||
## 关键表字段说明
|
||
|
||
### laravel_user(用户表)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | INT | 主键 |
|
||
| `tenant_id` | INT | 租户 ID(0=平台用户) |
|
||
| `code` | VARCHAR(100) | 用户编码 |
|
||
| `username` | VARCHAR(30) | 用户名(登录账号) |
|
||
| `password` | VARCHAR(255) | 密码(bcrypt 加密) |
|
||
| `salt` | VARCHAR(30) | 加密盐(外部盐,与 password 分离存储) |
|
||
| `realname` | VARCHAR(150) | 用户姓名 |
|
||
| `gender` | INT | 性别:1-男 2-女 3-保密 |
|
||
| `mobile` / `email` | VARCHAR(30) | 手机号 / 邮箱 |
|
||
| `avatar` | VARCHAR(255) | 用户头像 |
|
||
| `status` | INT | 状态:1-正常 2-禁用 |
|
||
| `dept_id` / `level_id` / `position_id` | INT | 部门 / 职级 / 岗位 ID |
|
||
| `province_code` / `city_code` / `district_code` / `street_code` | VARCHAR(30) | 省市县街道编码 |
|
||
| `city_info` | VARCHAR(255) | 省市区信息拼接 |
|
||
| `address` | VARCHAR(255) | 详细地址 |
|
||
| `intro` / `note` | VARCHAR(255) | 个人简介 / 备注 |
|
||
| `sort` | INT | 排序 |
|
||
| `is_delete` + 四个审计字段 | | 公共字段 |
|
||
|
||
**唯一索引(与软删除协同):**
|
||
|
||
```sql
|
||
UNIQUE INDEX uk_tenant_username (tenant_id, username, is_delete)
|
||
UNIQUE INDEX uk_tenant_mobile (tenant_id, mobile, is_delete)
|
||
UNIQUE INDEX uk_tenant_code (tenant_id, code, is_delete)
|
||
```
|
||
|
||
:::tip 为什么唯一索引含 is_delete?
|
||
软删除的用户 `is_delete=1` 仍占唯一索引——把 `is_delete` 纳入联合唯一后,同名账号删除后可重新注册(新记录 `is_delete=0` 不与已删记录冲突),同时保证**同租户内未删数据**用户名唯一。业务层的 `uniqueFields` 校验与数据库索引双保险。
|
||
:::
|
||
|
||
### laravel_role(角色表)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | INT | 主键 |
|
||
| `name` | VARCHAR(50) | 角色名称 |
|
||
| `code` | VARCHAR(50) | 角色编码 |
|
||
| `tenant_id` | INT | 租户 ID(角色按租户隔离) |
|
||
| `status` | TINYINT | 状态 |
|
||
| `remark` / `sort` | | 备注 / 排序 |
|
||
|
||
### laravel_menu(菜单/权限表)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | INT | 主键 |
|
||
| `parent_id` | INT | 父级 ID(0=顶级) |
|
||
| `name` | VARCHAR(50) | 菜单名称 |
|
||
| `permission` | VARCHAR(100) | 权限标识(如 `sys:user:add`,**菜单即权限**) |
|
||
| `type` | TINYINT | 类型:0=菜单/目录(可导航) 1=权限节点 |
|
||
| `path` | VARCHAR(200) | 路由路径 |
|
||
| `icon` | VARCHAR(100) | 图标 |
|
||
| `sort` / `status` / `remark` | | 排序 / 状态 / 备注 |
|
||
|
||
### laravel_tenant(租户表)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | INT | 主键 |
|
||
| `name` | VARCHAR(100) | 租户名称 |
|
||
| `code` | VARCHAR(50) | 租户编码(系统自动生成) |
|
||
| `status` | TINYINT | 状态(字典 tenant_status):0=禁用 1=启用 |
|
||
| `expire_time` | DATETIME | 过期时间(ResolveTenant 中间件校验) |
|
||
| `max_user_num` | INT | 最大用户数限制 |
|
||
| `contact_name` / `contact_phone` | | 联系人 / 联系电话 |
|
||
|
||
### laravel_article(文章表)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | INT | 主键 |
|
||
| `title` | VARCHAR(200) | 标题 |
|
||
| `category_id` | INT | 分类 ID |
|
||
| `cover` | VARCHAR(500) | 封面图路径 |
|
||
| `content` | TEXT | 内容(富文本,含 `[IMG_URL]` 占位符) |
|
||
| `author` | VARCHAR(50) | 作者 |
|
||
| `status` | TINYINT | 状态(字典 article_status) |
|
||
| `sort` | INT | 排序 |
|
||
| `tenant_id` | INT | 租户 ID |
|
||
|
||
## 索引策略
|
||
|
||
### 推荐索引
|
||
|
||
```sql
|
||
-- 用户表:高频查询字段(联合唯一索引见上文)
|
||
ALTER TABLE laravel_user ADD INDEX idx_tenant_id (tenant_id);
|
||
ALTER TABLE laravel_user ADD INDEX idx_dept_id (dept_id);
|
||
ALTER TABLE laravel_user ADD INDEX idx_status (status);
|
||
|
||
-- 角色关联表:外键索引
|
||
ALTER TABLE laravel_user_role ADD INDEX idx_user_id (user_id);
|
||
ALTER TABLE laravel_user_role ADD INDEX idx_role_id (role_id);
|
||
ALTER TABLE laravel_role_menu ADD INDEX idx_role_id (role_id);
|
||
ALTER TABLE laravel_role_menu ADD INDEX idx_menu_id (menu_id);
|
||
|
||
-- 文章表:常用过滤字段
|
||
ALTER TABLE laravel_article ADD INDEX idx_category_id (category_id);
|
||
ALTER TABLE laravel_article ADD INDEX idx_status (status);
|
||
ALTER TABLE laravel_article ADD INDEX idx_tenant_id (tenant_id);
|
||
|
||
-- 日志表:按时间查询
|
||
ALTER TABLE laravel_login_log ADD INDEX idx_create_time (create_time);
|
||
ALTER TABLE laravel_operation_log ADD INDEX idx_create_time (create_time);
|
||
ALTER TABLE laravel_job_log ADD INDEX idx_job_id (job_id);
|
||
|
||
-- 菜单表:树形查询
|
||
ALTER TABLE laravel_menu ADD INDEX idx_parent_id (parent_id);
|
||
|
||
-- 字典项表:按字典 ID 查询
|
||
ALTER TABLE laravel_dict_item ADD INDEX idx_dict_id (dict_id);
|
||
ALTER TABLE laravel_config_item ADD INDEX idx_config_id (config_id);
|
||
|
||
-- 城市表:按编码查询
|
||
ALTER TABLE laravel_city ADD INDEX idx_area_code (area_code);
|
||
ALTER TABLE laravel_city ADD INDEX idx_parent_code (parent_code);
|
||
```
|
||
|
||
### 索引设计原则
|
||
|
||
| 原则 | 说明 |
|
||
|------|------|
|
||
| 外键必加 | 所有 `_id` 外键字段都应加索引 |
|
||
| 过滤字段 | `pageEqFields` 中配置的精确匹配字段应加索引 |
|
||
| 模糊搜索 | `pageLikeFields` 中的字段可考虑全文索引,但 `LIKE '%xx%'` 无法用普通索引 |
|
||
| 排序字段 | `pageOrderBy` 中的默认排序字段可加索引 |
|
||
| 时间字段 | 日志表的 `create_time` 必加索引(按时间范围查询) |
|
||
| 联合唯一 | 软删除表的唯一约束必须含 `is_delete`(见上文) |
|
||
|
||
## 多数据库支持
|
||
|
||
### 支持的数据库
|
||
|
||
| 数据库 | `DB_CONNECTION` 值 | 默认端口 | PHP 扩展 |
|
||
|--------|---------|----------|----------|
|
||
| MySQL | `mysql` | 3306 | `pdo_mysql` |
|
||
| PostgreSQL | `pgsql` | 5432 | `pdo_pgsql` |
|
||
| SQL Server | `sqlsrv` | 1433 | `pdo_sqlsrv` |
|
||
| Oracle | `oracle` | 1521 | `pdo_oci`(自定义 oci 驱动接入) |
|
||
| SQLite | `sqlite` | - | `pdo_sqlite` |
|
||
|
||
### 切换数据库
|
||
|
||
只需修改 `.env` 文件,无需改动任何代码:
|
||
|
||
::: code-group
|
||
|
||
```ini [MySQL(默认)]
|
||
DB_CONNECTION=mysql
|
||
DB_HOST=127.0.0.1
|
||
DB_PORT=3306
|
||
DB_DATABASE=rxthinkcmf.laravel13.elevue
|
||
DB_USERNAME=root
|
||
DB_PASSWORD=root
|
||
DB_PREFIX=laravel_
|
||
```
|
||
|
||
```ini [PostgreSQL]
|
||
DB_CONNECTION=pgsql
|
||
DB_HOST=127.0.0.1
|
||
DB_PORT=5432
|
||
DB_DATABASE=rxthinkcmf.laravel13.elevue
|
||
DB_USERNAME=postgres
|
||
DB_PASSWORD=root
|
||
DB_PREFIX=laravel_
|
||
```
|
||
|
||
```ini [SQL Server]
|
||
DB_CONNECTION=sqlsrv
|
||
DB_HOST=127.0.0.1
|
||
DB_PORT=1433
|
||
DB_DATABASE=rxthinkcmf.laravel13.elevue
|
||
DB_USERNAME=sa
|
||
DB_PASSWORD=root
|
||
DB_PREFIX=laravel_
|
||
```
|
||
|
||
```ini [Oracle]
|
||
DB_CONNECTION=oracle
|
||
DB_HOST=127.0.0.1
|
||
DB_PORT=1521
|
||
DB_DATABASE=rxthinkcmf.laravel13.elevue
|
||
DB_USERNAME=root
|
||
DB_PASSWORD=root
|
||
DB_PREFIX=laravel_
|
||
```
|
||
|
||
```ini [SQLite]
|
||
DB_CONNECTION=sqlite
|
||
# DB_DATABASE 指向 database/database.sqlite(默认值)
|
||
DB_PREFIX=laravel_
|
||
```
|
||
|
||
:::
|
||
|
||
### 配置文件结构
|
||
|
||
```php
|
||
// config/database.php
|
||
return [
|
||
'default' => env('DB_CONNECTION', 'mysql'),
|
||
'connections' => [
|
||
'sqlite' => [...],
|
||
'mysql' => [...],
|
||
'pgsql' => [...],
|
||
'sqlsrv' => [...],
|
||
'oracle' => [...], // 自定义 oci 驱动(AppServiceProvider 注册 DB::extend)
|
||
],
|
||
];
|
||
```
|
||
|
||
:::tip Oracle 接入说明
|
||
Laravel 核心不内置 Oracle 连接器,项目通过 `AppServiceProvider` 中 `DB::extend('oci', ...)` 注册自定义驱动,配套 `App\Support\Database\{OracleConnection, OracleGrammar, OracleProcessor}` 完成分页语法与自增主键回填适配。切换前需安装 `pdo_oci` 扩展(见 [2.1 开发环境准备](/zh/quickstart/environment.html))。
|
||
:::
|
||
|
||
### 字段类型映射
|
||
|
||
| 通用类型 | MySQL | PostgreSQL | SQL Server | Oracle | SQLite |
|
||
|---------|-------|------------|------------|--------|--------|
|
||
| 自增主键 | `INT AUTO_INCREMENT` | `SERIAL` | `INT IDENTITY` | `NUMBER` + 序列/触发器 | `INTEGER PRIMARY KEY` |
|
||
| 字符串 | `VARCHAR(n)` | `VARCHAR(n)` | `NVARCHAR(n)` | `VARCHAR2(n)` | `TEXT` |
|
||
| 文本 | `TEXT` | `TEXT` | `NVARCHAR(MAX)` | `CLOB` | `TEXT` |
|
||
| 布尔 | `TINYINT(1)` | `BOOLEAN` | `BIT` | `NUMBER(1)` | `INTEGER` |
|
||
| 日期时间 | `DATETIME` | `TIMESTAMP` | `DATETIME2` | `TIMESTAMP` | `TEXT` |
|
||
| 小数 | `DECIMAL(m,n)` | `NUMERIC(m,n)` | `DECIMAL(m,n)` | `NUMBER(m,n)` | `REAL` |
|
||
|
||
:::tip 业务代码零修改
|
||
Eloquent 的方言层自动处理大部分 SQL 差异,切换数据库只需修改 `.env` 中的 `DB_CONNECTION`,业务代码无需任何修改。跨库 DDL 由 `DbSchemaBuilder` 按驱动生成(Oracle 自增序列与触发器自动创建)。
|
||
:::
|
||
|
||
### 各数据库安装
|
||
|
||
数据库的安装与初始化步骤已在 [2.1 开发环境准备](/zh/quickstart/environment.html)(含四平台安装命令、扩展启用、Oracle Instant Client)与 [2.5 数据库初始化](/zh/quickstart/database-init.html)(建库、脚本导入、`.env` 配置)中完整说明,此处不再重复。
|
||
|
||
## SQL 脚本
|
||
|
||
项目为每种数据库提供了独立的 SQL 脚本,存放在 `document/` 目录下按数据库类型分组:
|
||
|
||
```text
|
||
document/
|
||
├── mysql/
|
||
│ └── rxthinkcmf.laravel13.elevue.sql # MySQL 版本
|
||
├── postgresql/
|
||
│ └── rxthinkcmf.laravel13.elevue.sql # PostgreSQL 版本
|
||
├── sqlserver/
|
||
│ └── rxthinkcmf.laravel13.elevue.sql # SQL Server 版本
|
||
├── oracle/
|
||
│ └── rxthinkcmf.laravel13.elevue.sql # Oracle 版本
|
||
└── sqlite/
|
||
└── rxthinkcmf.laravel13.elevue.sql # SQLite 版本
|
||
```
|
||
|
||
各数据库脚本包含完整的表结构定义和初始数据(用户、角色、菜单、字典、城市行政区划等),已针对各数据库的 SQL 语法做了适配,可直接导入使用。
|
||
|
||
:::warning
|
||
本项目 `database/migrations/` 为空,**建表以 SQL 脚本为准**,`php artisan migrate` 不会创建业务表。导入方法详见 [2.5 数据库初始化](/zh/quickstart/database-init.html)。
|
||
:::
|
||
|
||
## 慢查询排查
|
||
|
||
```ini
|
||
# MySQL my.cnf / my.ini
|
||
slow_query_log = 1
|
||
slow_query_log_file = /var/log/mysql/slow.log
|
||
long_query_time = 2
|
||
```
|
||
|
||
:::warning 注意
|
||
项目所有查询都通过 Eloquent 查询构建器构建(参数绑定),不会出现原生 SQL 注入。如需排查慢查询,建议开启数据库慢查询日志,而非在代码层面埋点;同时核对 [索引策略](#索引策略) 中的推荐索引是否缺失。
|
||
:::
|