MyBatis-Plus 核心注解全解析:TableName、TableId、TableField、TableLogic
一、前言
MyBatis-Plus(MP)作为 MyBatis 的增强工具,通过一系列注解简化了实体类与数据库表之间的映射关系,无需编写复杂的 XML 配置即可实现灵活的字段映射、主键策略、逻辑删除等功能。本文将详细讲解 MP 中最常用的 4 个核心注解(@TableName、@TableId、@TableField、@TableLogic),结合实战场景说明其使用方式、解决的问题及核心原理,帮助开发者彻底掌握 MP 的注解体系。
二、@TableName:解决实体类与表名映射问题
MP 默认规则:实体类的类名即为数据库表名(大小写不敏感),但实际开发中表名往往带有前缀(如t_、tbl_)或与类名不一致,此时需通过@TableName注解指定实体类对应的表名。
2.1 问题场景
若数据库表名为t_user,而实体类名为User,直接使用 MP 的 CRUD 操作会抛出异常:
Table 'mybatis_plus.user' doesn't exist
原因:MP 默认操作user表,而非t_user表。
2.2 解决方案
方案 1:注解指定表名
在实体类上添加@TableName注解,明确映射的表名:
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("t_user") // 指定实体类对应的数据表名
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
方案 2:全局配置表名前缀(推荐)
若所有表都有统一前缀(如t_),可通过全局配置避免在每个实体类上添加@TableName:
# application.yml
mybatis-plus:
global-config:
db-config:
table-prefix: t_ # 所有实体类默认映射的表名 = 前缀 + 实体类名(如User → t_user)
配置后,实体类无需添加@TableName,MP 会自动拼接前缀生成表名。
2.3 核心注意事项
- 若表名包含特殊字符(如
user_info_2024),需直接在@TableName中写完整表名; - 全局前缀配置优先级低于
@TableName注解,即若实体类添加了@TableName,则以注解指定的表名为准。
三、@TableId:主键字段映射与主键策略
MP 默认将实体类中名为id的字段作为主键,并采用雪花算法自动生成主键值。若主键字段名或主键生成策略与默认规则不符,需通过@TableId注解配置。
3.1 问题场景 1:主键字段名非 id
若数据库表主键字段为uid,实体类属性也为uid,直接插入数据会抛出异常:
Field 'uid' doesn't have a default value
原因:MP 未识别uid为主键,未自动生成主键值。
解决方案
在uid属性上添加@TableId注解,标识其为主键:
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
@TableName("t_user")
public class User {
@TableId // 标识该字段为主键
private Long uid;
private String name;
private Integer age;
private String email;
}
3.2 问题场景 2:实体属性名与表主键名不一致
若实体类属性为id,但表主键字段为uid,需通过@TableId的value属性映射:
@TableId(value = "uid") // 实体属性id → 表字段uid
private Long id;
3.3 主键生成策略(type 属性)
@TableId的type属性用于指定主键生成策略,核心取值如下:
表格
| 策略值 | 描述 |
|---|---|
| IdType.ASSIGN_ID(默认) | 基于雪花算法生成 64 位 Long 型主键,与数据库是否自增无关 |
| IdType.AUTO | 使用数据库自增策略,需确保表主键字段设置为自增(如 MySQL 的 AUTO_INCREMENT) |
| IdType.INPUT | 手动输入主键值,插入数据时需手动设置主键 |
| IdType.UUID | 生成 32 位 UUID 字符串主键 |
示例 1:自增主键策略
@TableId(type = IdType.AUTO) // 主键自增
private Long id;
注意:需确保数据库表主键字段已设置自增,否则策略无效。
示例 2:全局配置主键策略
若所有表主键都采用自增策略,可通过全局配置统一设置:
# application.yml
mybatis-plus:
global-config:
db-config:
table-prefix: t_
id-type: auto # 全局默认主键自增
3.4 雪花算法深度解析
1. 应用背景
分布式系统中,水平分表后需保证全局主键唯一,传统的自增主键(单表唯一)、取模主键(扩容麻烦)无法满足需求,雪花算法应运而生。
2. 核心原理
雪花算法生成的主键是 64 位 Long 型整数,结构如下:
0 - 41位时间戳 - 10位机器ID - 12位序列号
- 1 位符号位:固定为 0,保证主键为正数;
- 41 位时间戳:存储当前时间与起始时间的差值,可使用约 69.7 年;
- 10 位机器 ID:5 位数据中心 ID + 5 位机器 ID,支持部署 1024 个节点;
- 12 位序列号:每毫秒内可生成 4096 个唯一 ID,避免同一节点同一毫秒生成重复 ID。
3. 优势
- 全局唯一:分布式环境下不同节点生成的 ID 不重复;
- 有序递增:按时间戳排序,利于数据库索引性能;
- 高性能:本地生成 ID,无需与数据库交互。
四、@TableField:普通字段映射
MP 默认规则:实体类属性名与表字段名一致(支持驼峰→下划线自动转换),若字段名不满足该规则,需通过@TableField注解映射。
4.1 场景 1:驼峰与下划线自动转换(无需注解)
MP 默认开启驼峰命名转换,例如:
- 实体类属性:
userName(驼峰)→ 表字段:user_name(下划线); - 等价于 MyBatis 配置:
configuration.map-underscore-to-camel-case=true。
4.2 场景 2:字段名完全不一致
若实体类属性为name,表字段为username,需通过@TableField指定映射关系:
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
@Data
@TableName("t_user")
public class User {
@TableId
private Long id;
@TableField("username") // 实体属性name → 表字段username
private String name;
private Integer age;
private String email;
}
4.3 扩展用法
@TableField(exist = false):标识该属性不对应表中任何字段(仅用于业务逻辑,不参与 CRUD);@TableField(select = false):查询时忽略该字段(避免查询大字段影响性能)。
示例:
@TableField(exist = false) // 该属性不映射数据库字段
private String temp;
@TableField(select = false) // 查询时不返回email字段
private String email;
五、@TableLogic:实现逻辑删除
5.1 逻辑删除 vs 物理删除
- 物理删除:直接删除数据库中的数据,无法恢复;
- 逻辑删除:假删除,仅修改表中 “删除状态字段” 的值(如
is_deleted=1),数据仍保留在库中,可恢复。
5.2 实现逻辑删除(三步法)
Step1:数据库添加逻辑删除字段
-- 为t_user表添加is_deleted字段,默认值0(未删除)
ALTER TABLE t_user ADD COLUMN is_deleted TINYINT(1) DEFAULT 0 COMMENT '逻辑删除标识:0-未删除 1-已删除';
Step2:实体类添加逻辑删除属性并注解
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
@Data
@TableName("t_user")
public class User {
@TableId
private Long id;
private String name;
private Integer age;
private String email;
@TableLogic // 标识该字段为逻辑删除字段
private Integer isDeleted; // 对应表字段is_deleted(驼峰自动转换)
}
Step3:全局配置(可选,默认值可省略)
# application.yml
mybatis-plus:
global-config:
db-config:
logic-delete-field: isDeleted # 全局逻辑删除字段名
logic-delete-value: 1 # 已删除值
logic-not-delete-value: 0 # 未删除值
5.3 测试逻辑删除
1. 删除操作(实际执行更新)
@Test
public void testLogicDelete() {
// 执行删除:DELETE FROM t_user WHERE id=?
// 实际执行:UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0
int result = userMapper.deleteById(1L);
System.out.println("受影响行数:" + result);
}
2. 查询操作(自动过滤已删除数据)
@Test
public void testSelect() {
// 执行查询:SELECT * FROM t_user
// 实际执行:SELECT * FROM t_user WHERE is_deleted=0
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println); // 不会显示is_deleted=1的数据
}
5.4 核心注意事项
- 逻辑删除仅影响 MP 的自动 CRUD 操作,自定义 SQL 需手动添加
is_deleted=0条件; - 若需查询已删除数据,需使用条件构造器手动指定
is_deleted=1; - 逻辑删除字段建议使用
TINYINT类型,默认值 0(未删除),删除后设为 1。
六、总结
关键点回顾
@TableName解决实体类与表名映射问题,推荐使用全局前缀配置减少注解冗余;@TableId用于主键映射和主键策略配置,雪花算法是分布式场景的首选主键策略;@TableField处理普通字段映射,支持驼峰自动转换和字段忽略配置;@TableLogic实现逻辑删除,避免数据物理删除,提升数据安全性和可恢复性。
MP 的注解体系核心是 “约定大于配置”,默认规则可满足大部分场景,特殊场景通过注解灵活配置,既简化了开发,又保证了灵活性。掌握这些核心注解,能大幅提升基于 MP 的开发效率!
更多推荐



所有评论(0)