四、常用注解

16 阅读4分钟

为什么要用 → 怎么用 → 常见坑 → 小练习


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 下划线
    userNameuser_name,MP 会做自动转换。
  • 情况2:不满足上述规则
    如实体 name ↔ 表字段 username,需要显式指定:
@TableField("username")
private String name;

3.2 常见坑

  • 查出来某字段总是 null:大概率就是字段映射没对上(尤其是“name ↔ username”这种不规则映射)。
  • 写条件时用错列名:建议后续学习 LambdaQueryWrapper,能减少字符串写错字段的风险(讲义后面章节有)。

4) @TableLogic:逻辑删除(假删)

4.1 逻辑删除 vs 物理删除

  • 物理删除:记录从表中真正删掉,之后查不到。
  • 逻辑删除:只更新“删除标记字段”的状态,数据还在表里,可恢复。

4.2 实现步骤

  1. 表里加一个逻辑删除字段(默认值 0)
  2. 实体类加对应属性并标注逻辑删除
  3. 测试删除与查询

讲义展示的效果:

  • 执行“删除”时实际是 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) 练习题

  1. 把表 user 改名为 t_user,运行 selectList(null),观察报错;然后用 @TableName("t_user") 修复。
  2. 把主键 id 改为 uid,跑插入,看是否出现 Field 'uid' doesn't have a default value;再用 @TableId 修复。
  3. 设置实体属性 name,表字段为 username,先不加注解看查询结果;再加 @TableField("username") 对比。
  4. 增加 is_deleted 字段并启用 @TableLogic,测试删除和查询日志里 SQL 的变化。