不建议用单表统一管理字典,应按业务域拆分为命名清晰的独立表;最小字段包括id、code、name、sort_order、is_enabled、created_at、updated_at;需通过外键约束、check、触发器及权限管控防误删乱改。

字典表该不该用单表统一管理
绝大多数通用项目里,不建议用一张 sys_dict 表存所有字典项。看似省事,实际带来字段语义模糊、索引失效、权限难控、SQL 冗长等问题。真正可维护的方案是按业务域拆分,比如 order_status、user_role、payment_method 这类命名清晰、职责单一的独立表。
每个字典表必须包含哪些字段
最小可用结构要覆盖查询、排序、状态控制三类需求,推荐固定字段组合:
-
id:主键,自增或 UUID(高并发下优先BIGINT UNSIGNED AUTO_INCREMENT) -
code:业务唯一编码,非数字型(如"paid"、"draft"),用于代码中硬引用,加唯一索引 -
name:前端展示名,允许局部多语言时可扩展为name_zh/name_en -
sort_order:整型,默认0,用于列表排序,避免用ORDER BY name做无意义字典排序 -
is_enabled:TINYINT(1),标记是否启用,比删数据更安全 -
created_at和updated_at:便于追溯变更,不是装饰字段
如何避免字典值被误删或乱改
核心是把约束前移到数据库层,而不是靠应用逻辑兜底:
- 对外键关联的字典字段(如
order.status_code),必须加FOREIGN KEY指向对应字典表的code字段,并设ON UPDATE CASCADE(改 code 时自动同步)和ON DELETE RESTRICT(禁止删在用字典项) - 对只读字典项(如固定支付方式),在表上加
CHECK (is_enabled = 1)并配合触发器拦截UPDATE/DELETE - 应用层写入字典数据前,先查
SELECT COUNT(*) FROM order_status WHERE code = 'shipped',别信“肯定有”
MySQL 8.0+ 可用但常被忽略的优化点
新版 MySQL 提供了更轻量的字典管理能力,不用额外建表也能满足部分场景:
- 枚举字段
ENUM('pending','processing','done')适合极稳定、无扩展预期的三五种状态,但注意它本质是字符串比较,ORDER BY按定义顺序而非字典序 - 生成列 + 虚拟索引:比如
status_label VARCHAR(20) AS (CASE status_code WHEN 'p' THEN '待处理' WHEN 'd' THEN '已完成' END) STORED,再对status_label建索引,避免每次查表翻译 - 系统变量模拟配置:用
SET PERSIST dict_user_role_admin = 'admin'存极少量全局开关,但别当字典表用——它不支持事务、不可查询、无权限隔离
CREATE TABLE order_status ( id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, code VARCHAR(32) NOT NULL UNIQUE, name VARCHAR(64) NOT NULL, sort_order INT DEFAULT 0, is_enabled TINYINT(1) DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_code_enabled (code, is_enabled), INDEX idx_sort (sort_order) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;字典表设计最易被绕开的其实是「谁有权改」——DBA 很少管应用侧字典变更流程,开发又常把
INSERT INTO user_role 当普通 SQL 写进初始化脚本,结果测试环境加了个 "test_admin",上线后权限失控。这类问题从建表那一刻起,就得和部署策略、权限审批一起定。










