MyBatis-Plus 实体类新增字段 会不会导致存量接口报错
在实际项目中,经常会遇到这种场景:某个实体类(例如 Person)已经在多个业务中大规模使用(Controller 出参、入参、Service、Mapper 等),但业务迭代需要给这个实体新增一个字段,比如新增 student_id(Java 字段一般写成 studentId),同时数据库表也要加一列。
本文总结一个核心问题:新增字段会不会让之前的存量接口查询报错? 以及如何做到平滑兼容上线。
1. 结论先行:查询一般不会报错,重点风险在写入
在使用 MyBatis-Plus 的前提下:
- ✅ 存量查询(SELECT)通常不会因为新增字段而报错
- ⚠️ 需要重点关注的是 存量写入(INSERT / UPDATE)是否会因为新增列约束导致失败
为什么会这样?
-
查询时,多出来的数据库列只是多返回一列,MP 会按实体字段映射:
- 实体类新增
studentId,就会接到值(或 null) - 不新增字段也不会报错(未映射的列被忽略)
- 实体类新增
-
写入时,如果数据库对新列有强约束(NOT NULL 且无默认值),存量代码没填该字段就会炸。
2. "存量查询会报错"的概率很低,但仍有特殊坑点
大多数情况下不会,但如果你们项目存在以下做法,可能会出现问题:
2.1 手写 ResultMap 或自定义字段映射错误
如果你们用了 resultMap 或复杂 join 的自定义 SQL,并且映射配置写错(字段名/类型不匹配),可能报错。
2.2 强类型/严格协议的客户端(非后端报错)
新增字段后接口返回 JSON 会多出 studentId。大部分客户端会忽略未知字段,但若对方消费者使用严格 schema 校验或强约束解析,可能出现兼容问题(这属于接口契约层面的风险)。
注意:这是"对方解析失败",不是后端查询报错。
3. 真正的高风险:你怎么加数据库字段决定存量写入是否崩
3.1 最危险做法(容易导致存量写入报错)
- 新增列
student_id设置为 NOT NULL - 并且 没有 DEFAULT 默认值
- 存量
insert(person)没给studentId赋值
这会导致数据库拒绝插入,典型错误类似:
Field 'student_id' doesn't have a default value- 或 NOT NULL 约束相关错误
3.2 推荐兼容做法(平滑上线)
新增列时采用以下之一:
- ✅ 允许 NULL:
student_id可为空 - ✅ 或提供 DEFAULT:给新列一个默认值
这样,即使旧业务不传 studentId,存量写入也不会失败。
4. 推荐上线步骤(最稳版本)
Step A:先改表(兼容方式)
先在数据库新增列,不要立刻加 NOT NULL(除非你已经保证所有写入都带值、并完成历史数据回填)。
例如(以字符串为例):
sql
ALTER TABLE person
ADD COLUMN student_id VARCHAR(64) NULL COMMENT '学号';
若是数字类型:
sql
ALTER TABLE person
ADD COLUMN student_id BIGINT NULL COMMENT '学号';
Step B:再改实体类(MP 字段映射)
在 Person 实体类中新增字段,注意字段名映射:
java
@TableField("student_id")
private String studentId; // 或 Long
Step C:不要在通用实体上直接加"必填校验"
如果你给 studentId 加了 @NotNull / @NotBlank 这类校验注解,而 Person 又作为很多接口的入参 DTO 使用,那么老接口请求没传 studentId 会直接 400 校验失败。
更稳做法 :
对"必须 studentId 的场景"使用专用 DTO(如 CreateStudentDTO / UpdateStudentDTO),不要把约束绑在全局复用的实体上。
5. 什么时候可以把 student_id 变成 NOT NULL?
一般建议分阶段:
- 第一阶段:新增列允许 NULL(兼容存量)
- 第二阶段:新业务开始写入时补齐该字段
- 第三阶段:对历史数据回填(update)
- 第四阶段:确认全量数据都有值后,再把列改成 NOT NULL(可选)
这样可以避免一次性改动造成系统大面积写入失败。
6. 总结
- MyBatis-Plus 下新增实体字段 + 数据库列,通常不会导致存量查询接口报错
- 真正需要重点防范的是:数据库新增列的 NOT NULL/DEFAULT 设计会不会让存量写入失败
- 最稳策略:新列先允许 NULL 或提供 DEFAULT,再逐步回填和收紧约束
- 对必填逻辑:用 DTO 控制约束,不要污染全局复用实体