数据库设计规范
1. 表设计规范
1.1 基础表结构
梵医云项目采用统一的表结构设计,所有业务表应继承基础字段。
sql
-- ✅ 符合规范的表设计
CREATE TABLE `system_users` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(50) NOT NULL COMMENT '用户账号',
`password` varchar(100) NOT NULL COMMENT '加密后的密码',
`nickname` varchar(50) DEFAULT NULL COMMENT '用户昵称',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`dept_id` bigint DEFAULT NULL COMMENT '部门ID',
`post_ids` json DEFAULT NULL COMMENT '岗位编号数组',
`email` varchar(50) DEFAULT NULL COMMENT '用户邮箱',
`mobile` varchar(11) DEFAULT NULL COMMENT '手机号码',
`sex` tinyint DEFAULT NULL COMMENT '用户性别',
`avatar` varchar(512) DEFAULT NULL COMMENT '用户头像',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '帐号状态',
`login_ip` varchar(50) DEFAULT NULL COMMENT '最后登录IP',
`login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
KEY `idx_dept_id` (`dept_id`),
KEY `idx_mobile` (`mobile`),
KEY `idx_status` (`status`),
KEY `idx_create_time` (`create_time`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='管理后台的用户'
ROW_FORMAT=DYNAMIC;1.2 基础字段说明
所有业务表必须包含以下基础字段:
| 字段名 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | bigint | 主键ID | 是 | AUTO_INCREMENT |
| tenant_id | bigint | 租户编号 | 是 | 0 |
| creator | varchar(64) | 创建者 | 否 | '' |
| create_time | datetime | 创建时间 | 是 | CURRENT_TIMESTAMP |
| updater | varchar(64) | 更新者 | 否 | '' |
| update_time | datetime | 更新时间 | 是 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
| deleted | bit(1) | 是否删除 | 是 | b'0' |
1.3 表命名规范
| 规则 | 说明 | 示例 |
|---|---|---|
| 模块前缀 | 表名以模块名开头 | system_users, infra_config |
| 下划线分隔 | 使用下划线分隔单词 | user_role, dept_post |
| 复数形式 | 实体表使用复数形式 | users, roles |
| 关系表 | 使用下划线连接两个表名 | user_role, role_menu |
示例:
system_users- 系统用户表system_dept- 系统部门表system_user_role- 用户角色关联表infra_config- 基础设施配置表infra_api_access_log- API访问日志表
2. 字段设计规范
2.1 字段命名规范
| 规则 | 说明 | 示例 |
|---|---|---|
| 小写字母 | 全部使用小写字母 | username, email |
| 下划线分隔 | 多个单词使用下划线分隔 | user_name, create_time |
| 布尔字段 | 以is_开头 | is_deleted, is_active |
| 时间字段 | 以_time结尾 | create_time, login_time |
| 日期字段 | 以_date结尾 | birth_date, login_date |
| ID字段 | 以_id结尾 | user_id, dept_id |
| 类型字段 | 以_type结尾 | user_type, status_type |
| 状态字段 | 以status结尾 | status, login_status |
2.2 字段类型规范
| 数据类型 | 使用场景 | 长度/精度 | 示例 |
|---|---|---|---|
| bigint | 主键、外键ID | 20 | id, user_id, dept_id |
| int | 状态、类型、数量 | 11 | status, type, sort |
| tinyint | 布尔值、小范围枚举 | 1 | deleted, sex |
| decimal | 金额、精确数值 | (10,2) | price, amount |
| varchar(n) | 变长字符串 | 根据实际需求 | username(50), email(100) |
| char(n) | 定长字符串 | 根据实际需求 | code(32) |
| text | 长文本 | 65535 | content, description |
| datetime | 日期时间 | - | create_time, update_time |
| timestamp | 时间戳 | - | login_time |
| json | JSON数据 | - | post_ids, extra_info |
| blob | 二进制数据 | - | file_data |
2.3 字段注释规范
所有字段必须添加注释,注释应清晰描述字段含义。
sql
-- ✅ 正确的字段注释
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
`username` varchar(50) NOT NULL COMMENT '用户账号',
`password` varchar(100) NOT NULL COMMENT '加密后的密码',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '帐号状态(0正常 1停用)',
-- ❌ 错误的字段注释
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
`username` varchar(50) NOT NULL COMMENT '名字',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态',2.4 特殊字段类型处理
2.4.1 JSON字段
对于数组或复杂对象,使用JSON类型存储:
sql
-- 存储岗位ID数组
`post_ids` json DEFAULT NULL COMMENT '岗位编号数组',
-- 存储扩展信息
`extra_info` json DEFAULT NULL COMMENT '扩展信息',在Java代码中使用 @TableField(typeHandler = JacksonTypeHandler.class) 注解处理:
java
@TableField(typeHandler = JacksonTypeHandler.class)
private Set<Long> postIds;2.4.2 布尔字段
使用 bit(1) 类型存储布尔值:
sql
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`visible` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否可见',在Java代码中使用 Boolean 类型:
java
@TableLogic
private Boolean deleted;2.4.3 金额字段
使用 decimal 类型存储金额,避免精度丢失:
sql
`price` decimal(10,2) DEFAULT NULL COMMENT '价格',
`amount` decimal(12,2) DEFAULT NULL COMMENT '金额',在Java代码中使用 BigDecimal 类型:
java
private BigDecimal price;
private BigDecimal amount;3. 索引设计规范
3.1 索引命名规范
| 索引类型 | 命名规则 | 示例 |
|---|---|---|
| 主键索引 | PRIMARY | PRIMARY KEY (id) |
| 唯一索引 | uk_字段名 | UNIQUE KEY uk_username (username) |
| 普通索引 | idx_字段名 | KEY idx_dept_id (dept_id) |
| 联合索引 | idx_字段1_字段2 | KEY idx_user_type_status (user_type, status) |
3.2 索引设计原则
sql
-- ✅ 正确的索引使用
-- 1. 主键自动创建索引
PRIMARY KEY (`id`)
-- 2. 唯一约束使用UNIQUE KEY
UNIQUE KEY `uk_username` (`username`)
UNIQUE KEY `uk_email` (`email`)
-- 3. 查询条件字段建立索引
KEY `idx_dept_id` (`dept_id`)
KEY `idx_status` (`status`)
-- 4. 联合索引注意顺序(最左前缀原则)
KEY `idx_user_type_status` (`user_type`, `status`)
-- 5. 时间字段建立索引(用于范围查询)
KEY `idx_create_time` (`create_time`)
-- 6. 外键字段建立索引
KEY `idx_tenant_id` (`tenant_id`)
-- ❌ 禁止的操作
-- 1. 禁止在WHERE条件中使用的字段不建索引
-- 2. 禁止在频繁更新的字段上建过多索引
-- 3. 禁止在区分度低的字段上建索引(如性别)
-- 4. 禁止索引数量超过表字段数的30%
-- 5. 禁止在LIKE '%xxx'查询的字段上建索引3.3 索引使用建议
| 场景 | 建议 | 示例 |
|---|---|---|
| 主键查询 | 自动索引 | WHERE id = 1 |
| 唯一性查询 | 唯一索引 | WHERE username = 'admin' |
| 范围查询 | 普通索引 | WHERE create_time > '2024-01-01' |
| 排序查询 | 联合索引 | ORDER BY create_time DESC |
| 多条件查询 | 联合索引 | WHERE type = 1 AND status = 0 |
| 模糊查询 | 前缀索引 | WHERE username LIKE 'admin%' |
4. 约束设计规范
4.1 主键约束
所有表必须有主键,推荐使用自增ID:
sql
PRIMARY KEY (`id`)对于Oracle、PostgreSQL等数据库,使用序列:
sql
@KeySequence("system_users_seq")4.2 唯一约束
对于需要唯一性的字段,使用唯一约束:
sql
UNIQUE KEY `uk_username` (`username`),
UNIQUE KEY `uk_email` (`email`),
UNIQUE KEY `uk_mobile` (`mobile`),4.3 非空约束
对于必填字段,设置NOT NULL:
sql
`username` varchar(50) NOT NULL COMMENT '用户账号',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '帐号状态',4.4 默认值
为字段设置合理的默认值:
sql
`status` tinyint NOT NULL DEFAULT '0' COMMENT '帐号状态',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',4.5 外键约束
项目不使用外键约束,通过应用层维护数据一致性:
sql
-- ❌ 不推荐使用外键约束
-- FOREIGN KEY (dept_id) REFERENCES system_dept(id)
-- ✅ 推荐通过应用层维护
-- 在Service层进行数据校验5. Java实体类映射规范
5.1 基础实体类
所有实体类应继承 TenantBaseDO 或 BaseDO:
java
@TableName(value = "system_users", autoResultMap = true)
@KeySequence("system_users_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AdminUserDO extends TenantBaseDO {
@TableId
private Long id;
private String username;
private String password;
private String nickname;
// ... 其他字段
}5.2 注解使用规范
| 注解 | 用途 | 示例 |
|---|---|---|
| @TableName | 指定表名 | @TableName("system_users") |
| @TableId | 标记主键 | @TableId |
| @KeySequence | 指定序列 | @KeySequence("system_users_seq") |
| @TableField | 标记字段 | @TableField("user_name") |
| @TableLogic | 逻辑删除 | @TableLogic |
| @TableField(typeHandler) | 类型处理器 | @TableField(typeHandler = JacksonTypeHandler.class) |
| @TableField(exist = false) | 非数据库字段 | @TableField(exist = false) |
5.3 基础字段映射
java
// BaseDO 基类包含以下字段:
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
private String creator;
@TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
private String updater;
@TableLogic
private Boolean deleted;
// TenantBaseDO 基类额外包含:
private Long tenantId;6. 数据库引擎规范
6.1 存储引擎
所有表使用 InnoDB 存储引擎:
sql
ENGINE=InnoDB6.2 字符集
使用 utf8mb4 字符集,支持存储emoji等特殊字符:
sql
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci6.3 行格式
使用 DYNAMIC 行格式:
sql
ROW_FORMAT=DYNAMIC7. 表设计示例
7.1 单表示例
sql
CREATE TABLE `system_dept` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '部门ID',
`name` varchar(50) NOT NULL COMMENT '部门名称',
`parent_id` bigint NOT NULL DEFAULT '0' COMMENT '父部门ID',
`sort` int NOT NULL DEFAULT '0' COMMENT '显示顺序',
`leader_user_id` bigint DEFAULT NULL COMMENT '负责人',
`phone` varchar(11) DEFAULT NULL COMMENT '联系电话',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '部门状态',
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_status` (`status`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='部门表'
ROW_FORMAT=DYNAMIC;7.2 关系表示例
sql
CREATE TABLE `system_user_role` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增编号',
`user_id` bigint NOT NULL COMMENT '用户ID',
`role_id` bigint NOT NULL COMMENT '角色ID',
`type` tinyint NOT NULL DEFAULT '1' COMMENT '角色类型',
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_role` (`user_id`, `role_id`),
KEY `idx_role_id` (`role_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='用户和角色关联表'
ROW_FORMAT=DYNAMIC;7.3 树形表示例
sql
CREATE TABLE `system_menu` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
`name` varchar(50) NOT NULL COMMENT '菜单名称',
`permission` varchar(100) DEFAULT NULL COMMENT '权限标识',
`type` tinyint NOT NULL COMMENT '菜单类型',
`sort` int NOT NULL DEFAULT '0' COMMENT '显示顺序',
`parent_id` bigint NOT NULL DEFAULT '0' COMMENT '父菜单ID',
`path` varchar(200) DEFAULT '' COMMENT '路由地址',
`icon` varchar(100) DEFAULT '#' COMMENT '菜单图标',
`component` varchar(255) DEFAULT NULL COMMENT '组件路径',
`component_name` varchar(255) DEFAULT NULL COMMENT '组件名',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '菜单状态',
`visible` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否可见',
`keep_alive` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否缓存',
`always_show` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否总是显示',
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_status` (`status`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
COMMENT='菜单权限表'
ROW_FORMAT=DYNAMIC;8. 数据库设计最佳实践
8.1 设计原则
- 遵循第三范式:消除传递依赖,减少数据冗余
- 适当反范式:为了性能考虑,可以适当冗余字段
- 字段最少化:只包含必要的字段,避免过度设计
- 命名一致性:保持命名风格的一致性
- 注释完整:为所有表和字段添加清晰的注释
8.2 性能优化
- 合理使用索引:为查询条件、排序字段建立索引
- 避免大表:单表数据量建议不超过1000万
- 分表分库:对于大表考虑分表分库策略
- 使用缓存:对于热点数据使用Redis缓存
- 避免全表扫描:查询条件尽量使用索引字段
8.3 安全规范
- 敏感字段加密:密码、手机号等敏感字段加密存储
- 逻辑删除:使用deleted字段标记删除,不物理删除
- 多租户隔离:通过tenant_id实现数据隔离
- 权限控制:在应用层实现数据权限控制
9. 常见问题
9.1 如何处理多租户?
所有业务表添加 tenant_id 字段,实体类继承 TenantBaseDO:
sql
`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
KEY `idx_tenant_id` (`tenant_id`)java
public class AdminUserDO extends TenantBaseDO {
// tenant_id 字段自动继承
}9.2 如何实现逻辑删除?
使用 deleted 字段标记删除状态:
sql
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',java
@TableLogic
private Boolean deleted;9.3 如何存储数组或复杂对象?
使用 JSON 类型存储:
sql
`post_ids` json DEFAULT NULL COMMENT '岗位编号数组',java
@TableField(typeHandler = JacksonTypeHandler.class)
private Set<Long> postIds;9.4 如何处理金额字段?
使用 decimal 类型,避免精度丢失:
sql
`price` decimal(10,2) DEFAULT NULL COMMENT '价格',java
private BigDecimal price;注意:本文档持续更新中,如有问题请及时反馈。
