Skip to content

数据库规范

概述

本规范定义了 RuoYi-Plus-UniApp 项目的数据库设计和使用标准,确保数据库结构一致性、可维护性和高性能。所有开发人员必须严格遵守本规范。

技术栈:

组件版本说明
MySQL8.0+主数据库(推荐)
PostgreSQL14.0+备选数据库
MyBatis-Plus3.5.14ORM框架
HikariCP5.0+连接池

规范等级:

  • 🔴 必须(MUST) - 强制执行,违反将导致代码审查不通过
  • 🟡 应该(SHOULD) - 强烈建议,特殊情况需说明原因
  • 🟢 建议(MAY) - 推荐做法,可根据实际情况调整

命名规范

1. 表命名规范

1.1 表名前缀 🔴

所有表必须使用模块前缀,前缀与模块对应关系如下:

前缀模块说明示例
sys_系统模块用户、角色、菜单、部门等sys_user, sys_role
b_基础业务通用业务表b_ad, b_bind
m_商城模块电商相关表m_goods, m_order
wf_工作流模块工作流引擎表wf_definition, wf_instance
gen_代码生成代码生成器表gen_table, gen_table_column
job_任务调度定时任务表job_info, job_log

1.2 表名格式 🔴

{前缀}_{业务名称}
{前缀}_{业务名称}_{子业务}

规则:

  • ✅ 全部小写字母
  • ✅ 单词间用下划线分隔
  • ✅ 使用名词或名词短语
  • ✅ 长度不超过30个字符
  • ❌ 禁止使用复数形式
  • ❌ 禁止使用SQL保留字
  • ❌ 禁止使用驼峰命名

正确示例:

sql
sys_user              -- 用户表
sys_user_role         -- 用户角色关联表
sys_oper_log          -- 操作日志表
sys_login_log         -- 登录日志表
m_goods_category      -- 商品分类表

错误示例:

sql
users                 -- ❌ 缺少前缀,使用复数
SysUser               -- ❌ 驼峰命名
sys_user_info_detail  -- ❌ 名称过长
user                  -- ❌ SQL保留字

1.3 关联表命名 🔴

中间表/关联表使用两个表名组合:

sql
sys_user_role         -- 用户-角色关联
sys_role_menu         -- 角色-菜单关联
sys_role_dept         -- 角色-部门关联
sys_user_post         -- 用户-岗位关联

2. 字段命名规范

2.1 字段名格式 🔴

{业务含义}_{类型后缀}

规则:

  • ✅ 全部小写字母
  • ✅ 单词间用下划线分隔
  • ✅ 使用有意义的名称
  • ✅ 长度不超过30个字符
  • ❌ 禁止使用单个字母
  • ❌ 禁止使用拼音
  • ❌ 禁止使用SQL保留字

2.2 标准后缀 🔴

后缀类型说明示例
_idBIGINT主键或外键user_id, dept_id
_nameVARCHAR名称user_name, dept_name
_codeVARCHAR编码post_code, role_key
_typeCHAR/VARCHAR类型user_type, menu_type
_timeDATETIME时间create_time, login_time
_dateDATE日期birth_date, expire_date
_byBIGINT操作人IDcreate_by, update_by
_urlVARCHARURL地址avatar_url, oper_url
_ipVARCHARIP地址login_ip, oper_ip
_numINT数量/序号order_num, sort_num
_countINT/BIGINT计数login_count, view_count

2.3 布尔字段命名 🔴

布尔字段使用 is_ 前缀:

sql
is_deleted            -- 是否删除
is_enabled            -- 是否启用
is_admin              -- 是否管理员
is_default            -- 是否默认
is_visible            -- 是否可见

2.4 保留字段名 🔴

以下字段名为系统保留,具有特定含义:

字段名类型说明必须
tenant_idVARCHAR(20)租户ID多租户表必须
is_deletedCHAR(1)逻辑删除标志所有业务表必须
create_deptBIGINT(20)创建部门所有业务表必须
create_byBIGINT(20)创建者所有业务表必须
create_timeDATETIME创建时间所有业务表必须
update_byBIGINT(20)更新者所有业务表必须
update_timeDATETIME更新时间所有业务表必须
remarkVARCHAR(500)备注可选
statusCHAR(1)状态按需

3. 索引命名规范

3.1 索引名格式 🔴

{索引类型}_{表名}_{字段名}
索引类型前缀说明示例
主键索引pk_PRIMARY KEYpk_sys_user
唯一索引uk_UNIQUE KEYuk_user_name
普通索引idx_INDEXidx_tenant_id
全文索引ft_FULLTEXTft_content

示例:

sql
-- 主键索引(自动创建)
PRIMARY KEY (user_id)

-- 唯一索引
CREATE UNIQUE INDEX uk_tenant_username ON sys_user(tenant_id, user_name);

-- 普通索引
CREATE INDEX idx_tenant_id ON sys_user(tenant_id);
CREATE INDEX idx_dept_id ON sys_user(dept_id);
CREATE INDEX idx_create_time ON sys_user(create_time);

-- 复合索引
CREATE INDEX idx_tenant_status_deleted ON sys_user(tenant_id, status, is_deleted);

字段类型规范

1. 主键类型 🔴

标准: 所有主键使用 BIGINT(20)

sql
user_id BIGINT(20) NOT NULL COMMENT '用户ID'

主键生成策略:

策略适用场景配置
雪花算法分布式系统(推荐)IdType.ASSIGN_ID
自增单机系统IdType.AUTO

禁止使用:

  • ❌ UUID (无序,性能差)
  • ❌ INT (容量不足)
  • ❌ 业务字段作为主键

2. 字符串类型 🔴

场景类型长度示例
手机号VARCHAR11phone VARCHAR(11)
姓名/账号VARCHAR30user_name VARCHAR(30)
邮箱VARCHAR50email VARCHAR(50)
编码/权限标识VARCHAR100role_key VARCHAR(100)
密码(加密后)VARCHAR100password VARCHAR(100)
URL/路径VARCHAR255avatar VARCHAR(255)
备注VARCHAR500remark VARCHAR(500)
祖级列表VARCHAR500ancestors VARCHAR(500)
长文本TEXT-content TEXT
超长文本LONGTEXT-detail LONGTEXT

选择原则:

  • ✅ 根据实际业务需求选择长度
  • ✅ 预留适当扩展空间
  • ❌ 禁止所有字段都用 VARCHAR(255)
  • ❌ 禁止 VARCHAR 超过 3000

3. 数值类型 🔴

场景类型说明示例
主键/外键BIGINT(20)支持千亿级user_id BIGINT(20)
数量/序号INT±21亿order_num INT
大数量BIGINT超大数值view_count BIGINT
金额DECIMAL(10,2)精确到分price DECIMAL(10,2)
百分比DECIMAL(5,2)0.00-100.00discount DECIMAL(5,2)

金额字段必须使用 DECIMAL:

sql
-- ✅ 正确
price DECIMAL(10,2) NOT NULL COMMENT '价格'
amount DECIMAL(12,2) NOT NULL COMMENT '金额'

-- ❌ 错误(精度丢失)
price FLOAT COMMENT '价格'
amount DOUBLE COMMENT '金额'

4. 时间类型 🔴

标准: 统一使用 DATETIME

sql
create_time DATETIME COMMENT '创建时间'
update_time DATETIME COMMENT '更新时间'
expire_time DATETIME COMMENT '过期时间'

禁止使用 TIMESTAMP:

对比项DATETIMETIMESTAMP
范围1000-9999年1970-2038年
时区不受影响受服务器时区影响
存储8字节4字节
推荐✅ 推荐❌ 禁止

5. 状态/标志类型 🔴

标准: 统一使用 CHAR(1)

sql
status CHAR(1) DEFAULT '1' COMMENT '状态(1正常 0停用)'
is_deleted CHAR(1) DEFAULT '0' COMMENT '是否删除(0正常 1删除)'
is_enabled CHAR(1) DEFAULT '1' COMMENT '是否启用(1是 0否)'

状态值约定:

字段含义
status'1'正常/启用
status'0'停用/禁用
is_deleted'0'未删除
is_deleted'1'已删除

禁止使用:

  • ❌ BOOLEAN / TINYINT(1)
  • ❌ INT 类型
  • ❌ 数字直接表示 (1/0)

6. 租户ID类型 🔴

sql
tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID'

租户ID规范:

  • 类型: VARCHAR(20)
  • 默认值: '000000' (主租户)
  • 格式: 6位数字字符串

表结构规范

1. 标准表结构模板 🔴

所有业务表必须包含以下结构:

sql
CREATE TABLE {前缀}_{表名} (
    -- ==================== 主键 ====================
    {主键名} BIGINT(20) NOT NULL COMMENT '主键ID',

    -- ==================== 租户字段(多租户表必须) ====================
    tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID',

    -- ==================== 业务字段 ====================
    -- ... 业务相关字段 ...

    -- ==================== 状态字段(按需) ====================
    status CHAR(1) DEFAULT '1' COMMENT '状态(1正常 0停用)',

    -- ==================== 逻辑删除(必须) ====================
    is_deleted CHAR(1) DEFAULT '0' COMMENT '是否删除(0正常 1删除)',

    -- ==================== 审计字段(必须) ====================
    create_dept BIGINT(20) DEFAULT NULL COMMENT '创建部门',
    create_by BIGINT(20) DEFAULT NULL COMMENT '创建者',
    create_time DATETIME COMMENT '创建时间',
    update_by BIGINT(20) DEFAULT NULL COMMENT '更新者',
    update_time DATETIME COMMENT '更新时间',

    -- ==================== 备注(可选) ====================
    remark VARCHAR(500) DEFAULT NULL COMMENT '备注',

    -- ==================== 主键约束 ====================
    PRIMARY KEY ({主键名})
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='表注释';

2. 字段顺序规范 🟡

字段按以下顺序排列:

  1. 主键字段
  2. 租户字段
  3. 外键字段
  4. 业务字段
  5. 状态字段
  6. 逻辑删除字段
  7. 审计字段
  8. 备注字段

3. 必须字段清单 🔴

字段类型默认值说明必须级别
{表名}_idBIGINT(20)-主键所有表必须
tenant_idVARCHAR(20)'000000'租户ID多租户表必须
is_deletedCHAR(1)'0'逻辑删除所有业务表必须
create_deptBIGINT(20)NULL创建部门所有业务表必须
create_byBIGINT(20)NULL创建者所有业务表必须
create_timeDATETIMENULL创建时间所有业务表必须
update_byBIGINT(20)NULL更新者所有业务表必须
update_timeDATETIMENULL更新时间所有业务表必须

4. 默认值规范 🔴

字段类型默认值说明
状态字段'1'默认正常/启用
删除标志'0'默认未删除
布尔字段'0'默认否
数值字段0 或 NULL根据业务语义
字符串'' 或 NULL空字符串或NULL
租户ID'000000'默认主租户
父级ID0顶级节点
排序号0默认排序

5. 注释规范 🔴

所有字段必须添加注释:

sql
-- ✅ 正确:完整的字段注释
user_id BIGINT(20) NOT NULL COMMENT '用户ID'
status CHAR(1) DEFAULT '1' COMMENT '状态(1正常 0停用)'
data_scope CHAR(1) DEFAULT '1' COMMENT '数据范围(1全部 2自定义 3本部门 4本部门及以下 5仅本人)'

-- ❌ 错误:缺少注释
user_id BIGINT(20) NOT NULL
status CHAR(1) DEFAULT '1'

注释内容要求:

  • ✅ 说明字段含义
  • ✅ 枚举值列出所有选项
  • ✅ 特殊含义说明(如-1表示不限制)
  • ✅ 单位说明(如金额单位为元)

表注释:

sql
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';

6. 树形结构规范 🟡

树形结构表必须包含:

sql
parent_id BIGINT(20) DEFAULT 0 COMMENT '父级ID'
ancestors VARCHAR(500) DEFAULT '' COMMENT '祖级列表'
order_num INT DEFAULT 0 COMMENT '显示顺序'

ancestors字段格式: 0,100,101,102 (逗号分隔的ID列表)

查询示例:

sql
-- 查询所有子节点
SELECT * FROM sys_dept WHERE FIND_IN_SET(100, ancestors);

-- 查询所有父节点
SELECT * FROM sys_dept WHERE dept_id IN (SELECT SUBSTRING_INDEX(ancestors, ',', -1) ...);

7. 日志表规范 🟡

日志表设计特点:

  • ❌ 不需要 update_by, update_time (日志不修改)
  • ✅ 可以冗余字段避免关联查询
  • ✅ 必须有时间索引
  • ✅ 考虑分区或定期归档
sql
CREATE TABLE sys_oper_log (
    oper_id BIGINT(20) NOT NULL COMMENT '日志ID',
    tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID',
    title VARCHAR(50) DEFAULT '' COMMENT '模块标题',
    oper_type CHAR(3) DEFAULT '' COMMENT '操作类型',
    oper_name VARCHAR(50) DEFAULT '' COMMENT '操作人员',
    dept_name VARCHAR(50) DEFAULT '' COMMENT '部门名称',  -- 冗余字段
    oper_url VARCHAR(255) DEFAULT '' COMMENT '请求URL',
    oper_ip VARCHAR(128) DEFAULT '' COMMENT '主机地址',
    oper_param TEXT COMMENT '请求参数',
    json_result TEXT COMMENT '返回参数',
    status CHAR(1) DEFAULT '1' COMMENT '操作状态',
    error_msg TEXT COMMENT '错误消息',
    oper_time DATETIME COMMENT '操作时间',
    cost_time BIGINT(20) DEFAULT 0 COMMENT '消耗时间(毫秒)',
    PRIMARY KEY (oper_id),
    KEY idx_oper_time (oper_time)
) ENGINE=InnoDB COMMENT='操作日志表';

索引规范

1. 索引创建原则 🔴

必须创建索引的场景:

  • ✅ 主键字段 (自动创建)
  • ✅ 外键字段
  • ✅ 租户ID字段 (多租户表)
  • ✅ WHERE 条件高频字段
  • ✅ ORDER BY / GROUP BY 字段
  • ✅ JOIN ON 条件字段
  • ✅ 唯一性约束字段

不应创建索引的场景:

  • ❌ 频繁更新的字段
  • ❌ 区分度低的字段 (如性别)
  • ❌ TEXT / BLOB 大字段
  • ❌ 极少查询的字段

2. 索引数量限制 🔴

  • 单表索引数量: 不超过5-8个
  • 复合索引字段数: 不超过5个
  • 定期清理无用索引

3. 必须创建的索引 🔴

sql
-- 1. 租户ID索引(所有多租户表)
CREATE INDEX idx_tenant_id ON {表名}(tenant_id);

-- 2. 外键索引
CREATE INDEX idx_dept_id ON sys_user(dept_id);
CREATE INDEX idx_parent_id ON sys_dept(parent_id);

-- 3. 状态+删除标志复合索引
CREATE INDEX idx_status_deleted ON {表名}(status, is_deleted);

-- 4. 创建时间索引(日志表)
CREATE INDEX idx_create_time ON {表名}(create_time);

4. 复合索引规范 🔴

最左前缀原则:

sql
-- 创建复合索引
CREATE INDEX idx_tenant_status_time ON sys_user(tenant_id, status, create_time);

-- ✅ 能使用索引
WHERE tenant_id = '000000'
WHERE tenant_id = '000000' AND status = '1'
WHERE tenant_id = '000000' AND status = '1' AND create_time > '2025-01-01'

-- ❌ 不能使用索引(跳过最左列)
WHERE status = '1'
WHERE create_time > '2025-01-01'
WHERE status = '1' AND create_time > '2025-01-01'

字段顺序原则:

  1. 等值查询字段在前
  2. 范围查询字段在后
  3. 区分度高的字段优先

5. 唯一索引规范 🔴

sql
-- 多租户场景:租户+业务字段联合唯一
CREATE UNIQUE INDEX uk_tenant_username ON sys_user(tenant_id, user_name);
CREATE UNIQUE INDEX uk_tenant_role_key ON sys_role(tenant_id, role_key);

-- 单租户场景:仅业务字段唯一
CREATE UNIQUE INDEX uk_config_key ON sys_config(config_key);

6. 索引失效场景 🔴

必须避免以下写法:

sql
-- ❌ 函数计算
WHERE YEAR(create_time) = 2025
-- ✅ 改为
WHERE create_time >= '2025-01-01' AND create_time < '2026-01-01'

-- ❌ 隐式类型转换
WHERE user_id = '1'  -- user_id是BIGINT
-- ✅ 改为
WHERE user_id = 1

-- ❌ LIKE前导通配符
WHERE user_name LIKE '%admin'
-- ✅ 改为
WHERE user_name LIKE 'admin%'

-- ❌ OR条件部分无索引
WHERE user_id = 1 OR nick_name = 'admin'
-- ✅ 改为UNION
SELECT * FROM sys_user WHERE user_id = 1
UNION
SELECT * FROM sys_user WHERE nick_name = 'admin'

-- ❌ NOT / != / <>
WHERE status != '0'
-- ✅ 改为IN
WHERE status IN ('1', '2')

SQL编写规范

1. 查询规范 🔴

1.1 禁止 SELECT *

sql
-- ❌ 禁止
SELECT * FROM sys_user WHERE user_id = 1;

-- ✅ 正确
SELECT user_id, user_name, nick_name, status
FROM sys_user
WHERE user_id = 1;

1.2 分页查询

sql
-- 普通分页(小数据量)
SELECT user_id, user_name FROM sys_user
ORDER BY create_time DESC
LIMIT 0, 10;

-- 深度分页优化(大数据量)
SELECT u.* FROM sys_user u
INNER JOIN (
    SELECT user_id FROM sys_user
    ORDER BY user_id
    LIMIT 100000, 10
) t ON u.user_id = t.user_id;

-- 游标分页(推荐)
SELECT user_id, user_name FROM sys_user
WHERE user_id > #{lastId}
ORDER BY user_id
LIMIT 10;

1.3 COUNT优化

sql
-- ❌ 慢查询
SELECT COUNT(*) FROM sys_oper_log;

-- ✅ 使用主键
SELECT COUNT(oper_id) FROM sys_oper_log WHERE status = '1';

-- ✅ 大表近似值
SELECT TABLE_ROWS FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'database_name' AND TABLE_NAME = 'sys_oper_log';

2. 写入规范 🔴

2.1 批量插入

sql
-- ❌ 循环单条插入
INSERT INTO sys_user (user_name) VALUES ('user1');
INSERT INTO sys_user (user_name) VALUES ('user2');
INSERT INTO sys_user (user_name) VALUES ('user3');

-- ✅ 批量插入
INSERT INTO sys_user (user_name) VALUES
    ('user1'),
    ('user2'),
    ('user3');

批量插入限制:

  • 单次批量: 不超过500-1000条
  • 超过数量: 分批执行

2.2 更新规范

sql
-- ✅ 明确WHERE条件
UPDATE sys_user SET status = '0' WHERE user_id = 1;

-- ❌ 禁止无WHERE条件的UPDATE
UPDATE sys_user SET status = '0';

2.3 删除规范

sql
-- ✅ 使用逻辑删除
UPDATE sys_user SET is_deleted = '1' WHERE user_id = 1;

-- ❌ 禁止物理删除(特殊场景除外)
DELETE FROM sys_user WHERE user_id = 1;

-- ❌ 禁止无WHERE条件的DELETE
DELETE FROM sys_user;

3. 关联查询规范 🟡

3.1 JOIN规范

sql
-- ✅ 正确:明确的JOIN条件
SELECT u.user_name, d.dept_name
FROM sys_user u
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
WHERE u.status = '1';

-- ❌ 禁止:隐式JOIN
SELECT u.user_name, d.dept_name
FROM sys_user u, sys_dept d
WHERE u.dept_id = d.dept_id;

3.2 JOIN数量限制

  • 单次查询JOIN表数: 不超过3-4个
  • 超过数量: 拆分为多次查询

3.3 子查询优化

sql
-- ❌ 不推荐:IN子查询
SELECT * FROM sys_user
WHERE dept_id IN (SELECT dept_id FROM sys_dept WHERE status = '1');

-- ✅ 推荐:改为JOIN
SELECT u.* FROM sys_user u
INNER JOIN sys_dept d ON u.dept_id = d.dept_id
WHERE d.status = '1';

4. 防注入规范 🔴

java
// ❌ 禁止:字符串拼接SQL
String sql = "SELECT * FROM sys_user WHERE user_name = '" + userName + "'";

// ✅ 正确:使用预编译
@Select("SELECT * FROM sys_user WHERE user_name = #{userName}")
SysUser selectByUserName(@Param("userName") String userName);

// ✅ 正确:使用MyBatis-Plus条件构造器
LambdaQueryWrapper<SysUser> wrapper = Wrappers.<SysUser>lambdaQuery()
    .eq(SysUser::getUserName, userName);

事务规范

1. 事务使用原则 🔴

必须使用事务的场景:

  • ✅ 涉及多表写操作
  • ✅ 需要保证数据一致性
  • ✅ 批量操作

不需要事务的场景:

  • ❌ 纯查询操作
  • ❌ 单表单条写入

2. 事务注解规范 🔴

java
// ✅ 正确:指定回滚异常
@Transactional(rollbackFor = Exception.class)
public void saveUser(SysUser user) {
    // 业务逻辑
}

// ❌ 错误:默认只回滚RuntimeException
@Transactional
public void saveUser(SysUser user) {
    // 业务逻辑
}

3. 事务范围原则 🔴

java
// ✅ 正确:事务范围最小化
@Transactional(rollbackFor = Exception.class)
public void updateUserRole(Long userId, List<Long> roleIds) {
    // 仅包含数据库操作
    userRoleMapper.deleteByUserId(userId);
    userRoleMapper.insertBatch(userId, roleIds);
}

// ❌ 错误:事务范围过大
@Transactional(rollbackFor = Exception.class)
public void updateUserRole(Long userId, List<Long> roleIds) {
    // 远程调用不应在事务中
    remoteService.notify(userId);

    userRoleMapper.deleteByUserId(userId);
    userRoleMapper.insertBatch(userId, roleIds);

    // 文件操作不应在事务中
    fileService.uploadFile(file);
}

4. 事务传播行为 🟡

传播行为说明适用场景
REQUIRED默认,有则加入,无则新建大多数场景
REQUIRES_NEW总是新建事务独立日志记录
NESTED嵌套事务部分回滚
NOT_SUPPORTED非事务执行查询操作
java
// 独立事务:日志记录不受主事务影响
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void saveOperLog(SysOperLog log) {
    operLogMapper.insert(log);
}

5. 避免长事务 🔴

java
// ❌ 错误:长事务
@Transactional(rollbackFor = Exception.class)
public void processData() {
    for (int i = 0; i < 10000; i++) {
        // 大量数据处理
        processItem(i);
    }
}

// ✅ 正确:分批处理
public void processData() {
    List<Integer> items = getItems();
    List<List<Integer>> batches = Lists.partition(items, 100);

    for (List<Integer> batch : batches) {
        processBatch(batch);  // 每批独立事务
    }
}

@Transactional(rollbackFor = Exception.class)
public void processBatch(List<Integer> batch) {
    for (Integer item : batch) {
        processItem(item);
    }
}

多租户规范

1. 租户字段规范 🔴

sql
-- 所有多租户表必须包含
tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID'

-- 必须创建租户索引
CREATE INDEX idx_tenant_id ON {表名}(tenant_id);

2. 租户隔离表清单 🔴

以下表必须支持多租户:

sys_user          -- 用户表
sys_role          -- 角色表
sys_dept          -- 部门表
sys_post          -- 岗位表
sys_menu          -- 菜单表(可选)
sys_dict_type     -- 字典类型
sys_dict_data     -- 字典数据
sys_config        -- 参数配置
sys_oss           -- 文件存储
sys_oper_log      -- 操作日志
sys_login_log     -- 登录日志

3. 非租户隔离表 🟡

以下表不需要租户隔离:

sys_tenant        -- 租户表本身
sys_tenant_package -- 租户套餐
gen_table         -- 代码生成表

4. 实体类规范 🔴

java
// 多租户表继承TenantEntity
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_user")
public class SysUser extends TenantEntity {

    @TableId(value = "user_id")
    private Long userId;

    // 其他字段...
}

// TenantEntity包含租户字段
public class TenantEntity extends BaseEntity {

    @TableField(tenantIdField = true)
    private String tenantId;
}

5. 跨租户查询 🟡

java
// 临时忽略租户隔离
TenantHelper.ignore(() -> {
    return baseMapper.selectList(null);
});

// 指定租户查询
TenantHelper.dynamic("000001", () -> {
    return baseMapper.selectList(null);
});

安全规范

1. SQL注入防护 🔴

java
// ❌ 禁止:字符串拼接
String sql = "SELECT * FROM sys_user WHERE user_name = '" + input + "'";

// ✅ 正确:预编译
@Select("SELECT * FROM sys_user WHERE user_name = #{userName}")
SysUser selectByUserName(@Param("userName") String userName);

// ✅ 正确:条件构造器
wrapper.eq(SysUser::getUserName, userName);

2. 敏感数据处理 🔴

java
// 密码字段:不参与常规查询
@TableField(
    insertStrategy = FieldStrategy.NOT_EMPTY,
    updateStrategy = FieldStrategy.NOT_EMPTY,
    whereStrategy = FieldStrategy.NOT_EMPTY
)
private String password;

// 查询时排除敏感字段
@Select("SELECT user_id, user_name, nick_name FROM sys_user")
List<SysUser> selectUserList();

3. 数据权限 🟡

java
// 使用数据权限注解
@DataPermission({
    @DataColumn(key = "deptName", value = "dept_id"),
    @DataColumn(key = "userName", value = "create_by")
})
public PageResult<SysUser> selectPageUserList(SysUserQuery query) {
    // 自动添加数据权限条件
}

4. 逻辑删除 🔴

java
// 实体类配置
@TableLogic
@TableField(value = "is_deleted", fill = FieldFill.INSERT)
private String isDeleted;

// 全局配置
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDeleted
      logic-delete-value: "1"
      logic-not-delete-value: "0"

性能规范

1. 查询优化 🔴

场景规范
字段选择只查需要的字段,禁止SELECT *
分页查询大数据量使用游标分页
关联查询JOIN不超过4个表
子查询优先使用JOIN替代
排序排序字段必须有索引

2. 连接池配置 🟡

yaml
spring:
  datasource:
    hikari:
      minimum-idle: 10           # 最小空闲连接
      maximum-pool-size: 50      # 最大连接数
      connection-timeout: 30000  # 连接超时(ms)
      idle-timeout: 600000       # 空闲超时(ms)
      max-lifetime: 1800000      # 最大存活时间(ms)

3. 慢查询标准 🔴

级别耗时处理要求
正常< 100ms无需处理
警告100ms - 1s需要关注
严重> 1s必须优化

4. 大表处理 🟡

  • 分区表: 按时间或业务维度分区
  • 冷热分离: 历史数据迁移到归档表
  • 定期归档: 超过6个月的日志数据归档

检查清单

新建表检查清单 ✅

  • [ ] 表名使用正确前缀
  • [ ] 表名全小写下划线分隔
  • [ ] 包含主键字段
  • [ ] 包含租户ID字段(多租户表)
  • [ ] 包含逻辑删除字段
  • [ ] 包含审计字段(create_by/create_time/update_by/update_time)
  • [ ] 所有字段有注释
  • [ ] 表有注释
  • [ ] 创建租户ID索引
  • [ ] 创建必要的业务索引
  • [ ] 使用正确的字段类型
  • [ ] 设置合理的默认值

SQL审查清单 ✅

  • [ ] 无SELECT *
  • [ ] 无字符串拼接SQL
  • [ ] 分页查询有优化
  • [ ] JOIN不超过4个表
  • [ ] WHERE条件字段有索引
  • [ ] 无索引失效写法
  • [ ] 批量操作分批执行
  • [ ] 事务范围合理

索引审查清单 ✅

  • [ ] 主键索引存在
  • [ ] 外键字段有索引
  • [ ] 租户ID有索引
  • [ ] 高频查询字段有索引
  • [ ] 复合索引顺序正确
  • [ ] 无冗余索引
  • [ ] 单表索引不超过8个

常见问题

1. 主键选择

问题: 应该使用自增ID还是雪花ID?

答案:

  • 分布式系统: 使用雪花ID (IdType.ASSIGN_ID)
  • 单机系统: 可使用自增ID (IdType.AUTO)
  • 推荐: 统一使用雪花ID,便于后续扩展

2. 逻辑删除与唯一索引冲突

问题: 逻辑删除后,唯一索引失效怎么办?

答案:

sql
-- 方案1: 唯一索引包含is_deleted
CREATE UNIQUE INDEX uk_tenant_username_deleted
ON sys_user(tenant_id, user_name, is_deleted);

-- 方案2: 删除时修改唯一字段
UPDATE sys_user
SET user_name = CONCAT(user_name, '_deleted_', UNIX_TIMESTAMP()),
    is_deleted = '1'
WHERE user_id = 1;

3. VARCHAR长度选择

问题: VARCHAR长度应该如何选择?

答案:

  • 根据实际业务需求选择
  • 预留20%-50%扩展空间
  • 常用长度参考本规范的字段类型部分
  • 不要盲目使用VARCHAR(255)

4. NULL vs 空字符串

问题: 字段应该用NULL还是空字符串?

答案:

  • NULL: 表示未知、不确定
  • 空字符串'': 表示已知为空
  • 建议: 字符串字段默认空字符串,外键/数值字段默认NULL

5. 索引过多影响性能

问题: 索引是否越多越好?

答案:

  • 不是,索引会影响INSERT/UPDATE/DELETE性能
  • 单表索引控制在5-8个以内
  • 定期分析索引使用情况,删除无用索引

总结

本规范涵盖了数据库设计和使用的核心要点:

  1. 命名规范 - 统一的表名、字段名、索引名命名规则
  2. 字段类型规范 - 标准化的数据类型选择
  3. 表结构规范 - 必须字段和标准模板
  4. 索引规范 - 索引创建原则和优化策略
  5. SQL编写规范 - 安全高效的SQL编写方式
  6. 事务规范 - 事务使用的最佳实践
  7. 多租户规范 - 多租户数据隔离要求
  8. 安全规范 - 防注入和数据保护
  9. 性能规范 - 性能优化标准

核心原则:

  • 🔴 必须遵守的规范是底线,不可违反
  • 🟡 应该遵守的规范是最佳实践,特殊情况需说明原因
  • 🟢 建议遵守的规范是推荐做法,可根据实际调整

通过遵守本规范,可以确保数据库设计的一致性、可维护性和高性能。