1. MyBatis-Plus注解体系概览
作为MyBatis的增强工具,MyBatis-Plus通过注解体系大幅简化了持久层开发。这些注解主要分为三大类:核心实体注解、条件构造注解和功能扩展注解。在实际项目中,合理使用这些注解可以减少约60%的传统XML配置工作量。
先看一个典型的用户实体类示例:
java复制@TableName("sys_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("username")
private String name;
@TableLogic
private Integer deleted;
}
这个简单示例已经包含了三个最基础的注解,接下来我们将深入解析每个注解的使用场景和实现原理。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心实体映射注解
2.1 @TableName:表名映射
当实体类名与数据库表名不一致时,@TableName注解显式指定映射关系。其核心属性包括:
- value:实际表名(必填)
- schema:数据库schema(多租户场景常用)
- keepGlobalPrefix:是否保持全局表前缀(配合全局配置使用)
特殊场景处理:
java复制// 动态表名场景(如分表)
@TableName("order_#{year}")
public class Order {
//...
}
// 多schema场景
@TableName(value = "users", schema = "tenant_1")
public class User {
//...
}
注意:在SpringBoot中,可以通过配置mybatis-plus.global-config.db-config.table-prefix设置全局表前缀,此时需要特别注意keepGlobalPrefix属性的配合使用。
2.2 @TableId:主键策略配置
主键策略是ORM框架的核心功能之一,@TableId提供了多种配置方式:
java复制public enum IdType {
AUTO, // 数据库ID自增
NONE, // 无状态,跟随全局
INPUT, // 手动输入
ASSIGN_ID, // 分配ID(默认雪花算法)
ASSIGN_UUID // 分配UUID
}
实际项目中的最佳实践:
java复制// 雪花算法ID(分布式系统推荐)
@TableId(type = IdType.ASSIGN_ID)
private Long id;
// 使用数据库自增(单机简单系统)
@TableId(type = IdType.AUTO)
private Integer id;
// 手动输入ID(如导入历史数据场景)
@TableId(type = IdType.INPUT)
private String customId;
2.3 @TableField:字段映射详解
字段映射是日常开发中最常用的注解,其属性配置丰富:
java复制@TableField(
value = "email", // 数据库字段名
exist = true, // 是否为数据库字段
condition = SqlCondition.LIKE, // 查询条件类型
fill = FieldFill.INSERT, // 自动填充策略
select = false, // 查询时是否包含
update = "now()", // 更新时固定值
insertStrategy = FieldStrategy.NOT_EMPTY, // 插入策略
updateStrategy = FieldStrategy.NOT_NULL // 更新策略
)
private String email;
自动填充的典型应用(创建时间/更新时间):
java复制@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
// 需要配合自定义处理器
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
3. 逻辑删除与版本控制
3.1 @TableLogic:优雅的逻辑删除
逻辑删除是现代系统的标配功能,MyBatis-Plus通过@TableLogic简化实现:
java复制@TableLogic
private Integer deleted;
// 配套的全局配置(application.yml)
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段
logic-not-delete-value: 0 # 未删除值
logic-delete-value: 1 # 删除值
实现原理:
- 查询自动追加条件:WHERE deleted=0
- 删除操作转为UPDATE语句
- 支持自定义值类型(String/Integer/Boolean等)
踩坑提示:当使用JOIN查询时,需要手动添加逻辑删除条件,框架无法自动处理关联表的逻辑删除状态。
3.2 @Version:乐观锁实现
并发控制是分布式系统的难点,乐观锁通过版本号实现:
java复制@Version
private Integer version;
配套的插件配置:
java复制@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
工作原理:
- 读取数据时获取version值
- 更新时自动附加条件:WHERE version=oldVersion
- 更新成功后version值自动+1
4. 复杂映射与类型处理
4.1 枚举类型处理
MyBatis-Plus提供了两种枚举处理方式:
- 普通枚举映射(默认存储枚举名称)
java复制public enum UserStatus {
ACTIVE, INACTIVE, LOCKED
}
private UserStatus status;
- 注解式枚举(存储自定义值)
java复制@Getter
public enum UserStatus {
@EnumValue("1") ACTIVE,
@EnumValue("0") INACTIVE,
@EnumValue("-1") LOCKED;
}
private UserStatus status;
配置枚举处理器:
java复制mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
4.2 复杂类型处理器
处理JSON字段等复杂类型:
java复制@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> attributes;
自定义类型处理器示例:
java复制public class AddressTypeHandler extends BaseTypeHandler<Address> {
// 实现四个抽象方法
}
@TableField(typeHandler = AddressTypeHandler.class)
private Address address;
5. 注解使用中的常见问题
5.1 注解失效排查指南
-
注解不生效的常见原因:
- 未添加@MapperScan扫描
- 实体类未被MyBatis管理
- 属性访问权限问题(需private+getter/setter)
- 与XML映射文件冲突
-
优先级问题:
- 注解配置 > XML配置 > 全局配置
- 字段注解 > 类注解
5.2 性能优化建议
- 避免过度使用自动填充(批量操作时会有性能损耗)
- 逻辑删除字段需要建立索引
- 乐观锁在高并发场景下可能引发大量重试
- 复杂类型处理会增加序列化/反序列化开销
5.3 与SpringBoot3的兼容问题
-
构造函数绑定问题:
- 需要保持无参构造函数
- 或使用@NoArgsConstructor/@AllArgsConstructor
-
记录操作日志的改进方案:
java复制@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new InnerInterceptor() {
@Override
public void beforeQuery(Executor executor, MappedStatement ms,
Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
BoundSql boundSql) {
// 记录查询日志
}
});
return interceptor;
}
在实际项目中,我们团队发现合理组合使用这些注解可以显著提升开发效率。特别是在微服务架构下,通过@TableField的condition属性可以快速实现动态查询,而@Version注解极大简化了分布式环境下的并发控制实现。不过需要注意,注解的灵活使用也需要配合良好的数据库设计,比如逻辑删除字段必须有索引,否则在大数据量下会出现性能问题。
