15 KiB
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 自动维护:
-- 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 |
关联关系:
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 |
关联关系:
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 |
关联关系:
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 + 四个审计字段 |
公共字段 |
唯一索引(与软删除协同):
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 |
索引策略
推荐索引
-- 用户表:高频查询字段(联合唯一索引见上文)
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
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=rxthinkcmf.laravel13.antdvue
DB_USERNAME=root
DB_PASSWORD=root
DB_PREFIX=laravel_
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=rxthinkcmf.laravel13.antdvue
DB_USERNAME=postgres
DB_PASSWORD=root
DB_PREFIX=laravel_
DB_CONNECTION=sqlsrv
DB_HOST=127.0.0.1
DB_PORT=1433
DB_DATABASE=rxthinkcmf.laravel13.antdvue
DB_USERNAME=sa
DB_PASSWORD=root
DB_PREFIX=laravel_
DB_CONNECTION=oracle
DB_HOST=127.0.0.1
DB_PORT=1521
DB_DATABASE=rxthinkcmf.laravel13.antdvue
DB_USERNAME=root
DB_PASSWORD=root
DB_PREFIX=laravel_
DB_CONNECTION=sqlite
# DB_DATABASE 指向 database/database.sqlite(默认值)
DB_PREFIX=laravel_
:::
配置文件结构
// 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 开发环境准备)。
:::
字段类型映射
| 通用类型 | 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 开发环境准备(含四平台安装命令、扩展启用、Oracle Instant Client)与 2.5 数据库初始化(建库、脚本导入、.env 配置)中完整说明,此处不再重复。
SQL 脚本
项目为每种数据库提供了独立的 SQL 脚本,存放在 document/ 目录下按数据库类型分组:
document/
├── mysql/
│ └── rxthinkcmf.laravel13.antdvue.sql # MySQL 版本
├── postgresql/
│ └── rxthinkcmf.laravel13.antdvue.sql # PostgreSQL 版本
├── sqlserver/
│ └── rxthinkcmf.laravel13.antdvue.sql # SQL Server 版本
├── oracle/
│ └── rxthinkcmf.laravel13.antdvue.sql # Oracle 版本
└── sqlite/
└── rxthinkcmf.laravel13.antdvue.sql # SQLite 版本
各数据库脚本包含完整的表结构定义和初始数据(用户、角色、菜单、字典、城市行政区划等),已针对各数据库的 SQL 语法做了适配,可直接导入使用。
:::warning
本项目 database/migrations/ 为空,建表以 SQL 脚本为准,php artisan migrate 不会创建业务表。导入方法详见 2.5 数据库初始化。
:::
慢查询排查
# 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 注入。如需排查慢查询,建议开启数据库慢查询日志,而非在代码层面埋点;同时核对 索引策略 中的推荐索引是否缺失。 :::