为什么要用 → 怎么用 → 常见坑 → 小练习
0. 先建立一个核心认知:MP 默认怎么“猜表/猜字段/猜主键”?
- 表名默认 = 实体类类名(通常按规则转表名) :MP 通过
BaseMapper<User>的泛型知道你要操作哪个实体,从而推断要操作的表。 - 主键默认 = id:做 CRUD 时默认把
id当主键列;插入时默认使用雪花算法等策略生成 id。 - 字段默认 = 属性名 ↔ 表字段名(有一定命名转换能力) :如果不一致就会出映射问题,需要注解介入。
1) @TableName:告诉 MP “这张实体对应哪张表”
1.1 什么时候需要?
当实体类名和真实表名不一致时就需要。讲义举例:把表 user 改名为 t_user 后,MP 仍按默认去查 user,会报 “表不存在”。
1.2 怎么用(实体类上标注)
@TableName("t_user")
public class User { ... }
这样 MP 就能正确生成对 t_user 的 SQL。
1.3 更常用的做法:全局表前缀(少写注解)
如果你的表普遍有固定前缀(例如 t_ / tbl_),可以用全局配置统一处理,避免每个实体都写 @TableName。
application.yml 示例:
mybatis-plus:
global-config:
db-config:
table-prefix: t_
1.4 常见坑
- 你明明操作
t_user,日志里却是FROM user:说明表映射没配好(缺@TableName或缺全局前缀)。 - 项目里混用:有的表有前缀有的没有 → 建议统一命名,或者对个别例外再写
@TableName。
2) @TableId:告诉 MP “谁才是主键 + 主键列名 + 主键策略”
2.1 什么时候需要?
- 主键不是
id,而是uid/user_id等:MP 不会自动把uid当主键,插入时可能报 “没有默认值”。讲义案例把id改为uid后出现Field 'uid' doesn't have a default value。
2.2 怎么用(在主键属性上标注)
@TableId
private Long uid;
把该属性标识为主键即可。
2.3 value 属性:属性名和列名不一致时必用
讲义说明:如果实体里主键属性叫 id,但表里主键列叫 uid,只写 @TableId 会导致 SQL 用错列名并报错,需要指定列名。
@TableId("uid")
// 或 @TableId(value="uid")
private Long id;
2.4 type 属性:主键生成策略
讲义给了两个常用策略(你最常遇到的也是这俩):
IdType.ASSIGN_ID(默认):基于雪花算法生成 id,与数据库是否自增无关。IdType.AUTO:使用数据库自增,要求数据库真的设置了自增,否则无效。
示例:
@TableId(value="id", type = IdType.AUTO)
private Long id;
2.5 全局主键策略(项目级统一)
也可以全局配置主键策略(讲义示例)。
mybatis-plus:
global-config:
db-config:
id-type: auto
2.6 常见坑速查
- 报 Unknown column 'id' :多半是表里叫
uid,你没用@TableId(value="uid")指定列名。 - 报 Field 'uid' doesn't have a default value:你把主键改成
uid但 MP 没识别到它是主键(缺@TableId或策略不对)。
3) @TableField:告诉 MP “这个属性对应哪个字段(列)”
3.1 什么时候需要?
当实体属性名和表字段名不一致时。讲义总结了两种情况:
- 情况1:驼峰 vs 下划线
如userName↔user_name,MP 会做自动转换。 - 情况2:不满足上述规则
如实体name↔ 表字段username,需要显式指定:
@TableField("username")
private String name;
3.2 常见坑
- 查出来某字段总是
null:大概率就是字段映射没对上(尤其是“name ↔ username”这种不规则映射)。 - 写条件时用错列名:建议后续学习
LambdaQueryWrapper,能减少字符串写错字段的风险(讲义后面章节有)。
4) @TableLogic:逻辑删除(假删)
4.1 逻辑删除 vs 物理删除
- 物理删除:记录从表中真正删掉,之后查不到。
- 逻辑删除:只更新“删除标记字段”的状态,数据还在表里,可恢复。
4.2 实现步骤
- 表里加一个逻辑删除字段(默认值 0)
- 实体类加对应属性并标注逻辑删除
- 测试删除与查询
讲义展示的效果:
- 执行“删除”时实际是
UPDATE ... SET is_deleted=1 ... - 查询时默认带上
is_deleted=0,逻辑删除的数据不会查出来
实体示例(思路):
@TableLogic
private Integer isDeleted;
4.3 常见坑
- 你觉得“删了怎么表里还有”:逻辑删除就是这样,它是“可恢复”的方案。
- 你写自定义 SQL/复杂查询时忘记加
is_deleted=0:MP 自动拼接主要发生在它接管的查询里,自定义 SQL 要自己注意一致性。
5) 一页速记清单
- 表名不一致:
@TableName("真实表名")或全局table-prefix - 主键不是 id / 主键列名不同:
@TableId(value="列名", type=策略) - 字段名不一致且不属于驼峰下划线转换:
@TableField("列名") - 需要假删:
@TableLogic+ 表字段默认 0,删变更、查过滤
6) 练习题
- 把表
user改名为t_user,运行selectList(null),观察报错;然后用@TableName("t_user")修复。 - 把主键
id改为uid,跑插入,看是否出现Field 'uid' doesn't have a default value;再用@TableId修复。 - 设置实体属性
name,表字段为username,先不加注解看查询结果;再加@TableField("username")对比。 - 增加
is_deleted字段并启用@TableLogic,测试删除和查询日志里 SQL 的变化。