本篇整理阿里 Java 开发手册中 MySQL 数据库规约和工程结构规范部分,重点是索引、SQL 写法和分层规范。
一、建表规约
三个必备字段
手册要求每张业务表都有:
1 | id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', |
create_time 和 update_time 是排查数据问题的最基础手段,缺了就没法知道数据什么时候写入、什么时候被改。
不允许外键
手册明确禁止在数据库层面定义外键(FOREIGN KEY)。原因:
- 外键约束在高并发写入时会产生额外的锁竞争
- 迁移和 DDL 变更时外键依赖关系复杂
- 一致性改由应用层保证
字段不允许为 NULL(有默认值代替)
1 | -- 错误 |
原因:NULL 值在索引、统计、判断时有很多反直觉的行为,比如 NULL != NULL,COUNT(列名) 不统计 NULL 等。
二、索引规约
业务唯一字段必须建唯一索引
1 | -- 哪怕应用层已经有唯一校验,数据库层也要建唯一索引 |
应用层校验 + 数据库唯一索引是双保险:应用层做并发校验(先查后写之间有时间窗口),数据库做最终保障。
索引命名规范
| 类型 | 命名格式 | 示例 |
|---|---|---|
| 主键索引 | pk_字段名 | pk_id |
| 唯一索引 | uk_字段名 | uk_order_no |
| 普通索引 | idx_字段名 | idx_user_id |
最左前缀原则
联合索引 (a, b, c),以下查询可以用到索引:
WHERE a = ?WHERE a = ? AND b = ?WHERE a = ? AND b = ? AND c = ?
以下无法用到索引:
WHERE b = ?(跳过了 a)WHERE b = ? AND c = ?(跳过了 a)
建联合索引时,区分度高的字段放左边,查询条件最常用的字段放左边。
避免索引失效的常见写法
1 | -- 在索引列上做函数运算,索引失效 |
三、SQL 规约
SELECT 不要用 *
1 | -- 错误 |
原因:
SELECT *会读取所有列,包括大字段(TEXT、BLOB),增加网络传输量- 表结构变化后,
*的含义悄悄改变,容易引入 bug - 无法使用覆盖索引优化
禁止超过 3 张表的 JOIN
超过 3 张表的 JOIN 优化器难以选择最优执行计划,且索引设计往往需要针对 JOIN 条件特殊处理。
解法:把 JOIN 拆成多次查询,在应用层组装。这也符合微服务架构下”跨服务数据不做 JOIN”的原则。
分页查询的深度分页问题
1 | -- 当 offset 很大时,MySQL 仍然要扫描 offset+limit 行再丢弃前面的 |
四、工程结构规范
分层职责
手册定义的标准分层:
1 | Controller ← 参数校验、协议转换(HTTP/RPC),不写业务逻辑 |
超过 5 个参数用 DTO 封装
1 | // 错误:参数列表过长,调用时容易搞错顺序 |
Service 和 ServiceImpl 分离
手册要求:
UserService(接口)放在service包UserServiceImpl(实现)放在service.impl包
好处:便于 Mock 测试,便于多实现切换(如 A/B 两套实现)。
小结
手册的 MySQL 规约背后都有实际的性能或稳定性原因,不是为了规范而规范。理解了为什么,比死记规则更有价值:外键禁止是因为锁竞争,SELECT * 禁止是因为性能和可维护性,深度分页改游标是因为全表扫描。
至此阿里 Java 开发手册三篇整理完成,覆盖了编程规约、并发异常、MySQL 和工程结构四个核心模块。



