当前位置: 首页 > news >正文

MyBatisPlus之核心注解与配置

MyBatisPlus之核心注解与配置详解

    • 一、核心注解:实体类与数据库的桥梁
      • 1.1 @TableName:指定表名映射
      • 1.2 @TableId:主键映射与生成策略
      • 1.3 @TableField:普通字段映射
      • 1.4 @TableLogic:逻辑删除
      • 1.5 @Version:乐观锁
      • 1.6 @EnumValue:枚举类型映射
    • 二、全局配置:定制MyBatisPlus行为
      • 2.1 核心全局配置(application.yml)
      • 2.2 关键配置详解
        • 2.2.1 基础配置
        • 2.2.2 数据库配置(db-config)
    • 三、元对象处理器:实现自动填充
      • 3.1 实现元对象处理器
      • 3.2 使用自动填充
    • 四、插件配置:增强MP功能
      • 4.1 分页插件(PaginationInnerInterceptor)
      • 4.2 乐观锁插件(OptimisticLockerInnerInterceptor)
      • 4.3 防全表更新插件(BlockAttackInnerInterceptor)
    • 五、实战场景:注解与配置组合使用
      • 5.1 完整实体类示例
      • 5.2 全局配置最佳实践
    • 六、常见问题与避坑指南
      • 6.1 注解与全局配置冲突
      • 6.2 自动填充失效
      • 6.3 分页查询无数据
      • 6.4 逻辑删除后查询仍能返回数据
      • 总结

MyBatisPlus(简称MP)作为MyBatis的增强工具,通过注解和配置简化了数据库操作,大幅提升开发效率,其中核心注解用于实体类与数据库表的映射,而配置则决定了MP的行为模式。

一、核心注解:实体类与数据库的桥梁

MyBatisPlus的注解主要用于实体类与数据库表的映射,替代传统MyBatis的XML映射文件中的resultMap配置。掌握这些注解是使用MP的基础。

1.1 @TableName:指定表名映射

功能:将实体类与数据库表名关联,解决类名与表名不一致问题。

使用场景

  • 实体类名与表名不同(如实体类User对应表sys_user);
  • 表名包含特殊字符(如下划线);
  • 多数据源场景下指定表所在的数据库。

示例

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@Data
// 实体类User对应数据库表sys_user
@TableName("sys_user") 
public class User {private Long id;private String username;
}

进阶配置

// 多数据源场景:指定表所在的数据库(如MySQL的db1库)
@TableName(value = "sys_user", schema = "db1") 
public class User { ... }

注意:若实体类名与表名一致(忽略大小写),可省略此注解。

1.2 @TableId:主键映射与生成策略

功能:标记实体类中的主键字段,并指定主键生成策略(如自增、雪花算法等)。

核心属性

  • value:主键字段名(实体类字段与表字段不一致时使用);
  • type:主键生成策略(IdType枚举)。

主键生成策略(IdType)

策略说明适用场景
AUTO数据库自增(需表字段设置自增)单数据源,简单业务
ASSIGN_IDMP生成雪花算法ID(Long类型,分布式唯一)分布式系统,多数据源
ASSIGN_UUIDMP生成UUID(不含中划线,String类型)需字符串主键场景
INPUT手动输入主键值主键由业务逻辑生成
NONE未设置策略(默认跟随全局配置)-

示例

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;@Data
@TableName("sys_user")
public class User {// 主键字段id,对应表字段user_id,使用雪花算法生成@TableId(value = "user_id", type = IdType.ASSIGN_ID)private Long id;private String username;
}

最佳实践

  • 分布式系统优先使用ASSIGN_ID(雪花算法);
  • 单库单表可使用AUTO(数据库自增);
  • 避免手动输入主键(INPUT),易导致重复。

1.3 @TableField:普通字段映射

功能:配置实体类字段与数据库表字段的映射关系,支持忽略字段、自动填充等功能。

核心属性

  • value:表字段名(字段名不一致时使用);
  • exist:是否为数据库表字段(false表示忽略此字段);
  • fill:自动填充策略(FieldFill枚举,配合元对象处理器使用);
  • select:查询时是否包含此字段(false表示查询时不返回);
  • update:更新时是否包含此字段(false表示更新时不修改)。

自动填充策略(FieldFill)

  • DEFAULT:不自动填充;
  • INSERT:插入时填充;
  • UPDATE:更新时填充;
  • INSERT_UPDATE:插入和更新时均填充(如更新时间)。

示例

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.time.LocalDateTime;@Data
@TableName("sys_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;// 实体类字段name对应表字段username@TableField(value = "username")private String name;// 忽略此字段(非数据库表字段)@TableField(exist = false)private String tempData;// 插入时自动填充(如创建时间)@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 插入和更新时自动填充(如更新时间)@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;// 查询时不返回此字段(如密码)@TableField(select = false)private String password;
}

注意:自动填充需配合元对象处理器MetaObjectHandler)使用,详见下文“全局配置”。

1.4 @TableLogic:逻辑删除

功能:标记逻辑删除字段,实现“假删除”(更新字段值而非物理删除)。

逻辑删除原理

  • 删除操作:DELETE FROM table WHERE id = ? → 转为 UPDATE table SET is_deleted = 1 WHERE id = ?
  • 查询操作:自动添加条件 AND is_deleted = 0,过滤已删除数据。

示例

import com.baomidou.mybatisplus.annotation.TableLogic;@Data
@TableName("sys_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String username;// 逻辑删除字段(0:未删除,1:已删除)@TableLogicprivate Integer isDeleted;
}

配合全局配置

# application.yml
mybatis-plus:global-config:db-config:logic-delete-field: isDeleted # 全局逻辑删除字段名(默认is_deleted)logic-delete-value: 1 # 已删除值logic-not-delete-value: 0 # 未删除值

注意

  • 逻辑删除字段类型通常为IntegerBoolean
  • 自定义SQL需手动添加逻辑删除条件(AND is_deleted = 0)。

1.5 @Version:乐观锁

功能:标记乐观锁版本字段,解决并发更新冲突问题。

乐观锁原理

  • 更新时添加条件 WHERE version = 旧版本号
  • 更新成功后自动将版本号+1;
  • 若版本号不匹配(已被其他线程修改),则更新失败。

示例

import com.baomidou.mybatisplus.annotation.Version;@Data
@TableName("sys_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String username;// 乐观锁版本字段@Versionprivate Integer version;
}

注意:需单独配置乐观锁插件才能生效(见下文“插件配置”)。

1.6 @EnumValue:枚举类型映射

功能:指定枚举类中与数据库字段对应的属性,实现枚举与数据库值的映射。

使用场景:数据库存储枚举的编码值(如1代表ENABLE0代表DISABLE),实体类使用枚举类型。

示例

  1. 定义枚举类:
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;@Getter
public enum StatusEnum {ENABLE(1, "启用"),DISABLE(0, "禁用");// 数据库存储的编码值@EnumValue private final Integer code;// 枚举描述(非数据库字段)private final String desc;StatusEnum(Integer code, String desc) {this.code = code;this.desc = desc;}
}
  1. 在实体类中使用:
@Data
@TableName("sys_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String username;// 枚举类型字段(数据库存储code值)private StatusEnum status;
}

效果

  • 插入时:user.setStatus(StatusEnum.ENABLE) → 数据库存储1
  • 查询时:数据库1 → 自动转换为StatusEnum.ENABLE

二、全局配置:定制MyBatisPlus行为

MyBatisPlus的全局配置通过application.yml(或application.properties)实现,用于统一设置主键策略、逻辑删除、驼峰映射等行为,减少重复注解配置。

2.1 核心全局配置(application.yml)

mybatis-plus:# 1. 基础配置type-aliases-package: com.example.mp.entity # 实体类包路径(别名)mapper-locations: classpath:mapper/*.xml # MapperXML文件路径type-handlers-package: com.example.mp.handler # 类型处理器包路径configuration:map-underscore-to-camel-case: true # 驼峰命名转换(默认true)log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志实现(开发环境)cache-enabled: false # 是否开启二级缓存(默认true)# 2. 全局数据库配置global-config:db-config:id-type: ASSIGN_ID # 全局主键策略(默认NONE)table-prefix: sys_ # 表名前缀(实体类User → 表sys_user)schema: db1 # 数据库名(多数据源时指定)column-format: `%s` # 字段格式化(如MySQL反引号包裹)logic-delete-field: isDeleted # 全局逻辑删除字段名logic-delete-value: 1 # 已删除值logic-not-delete-value: 0 # 未删除值update-strategy: NOT_NULL # 更新策略(只更新非空字段)insert-strategy: NOT_NULL # 插入策略(非空字段才插入)# 3.  banner配置(启动时是否显示MP logo)banner: false

2.2 关键配置详解

2.2.1 基础配置
  • type-aliases-package:指定实体类包路径,XML中可直接使用类名作为别名(如resultType="User");
  • mapper-locations:指定MapperXML文件位置,若全用注解写SQL可省略;
  • map-underscore-to-camel-case:自动将数据库字段user_name映射为实体类userName(默认开启);
  • log-impl:配置日志实现(开发环境用StdOutImpl打印SQL,生产环境关闭)。
2.2.2 数据库配置(db-config)
  • id-type:全局主键策略,优先级低于实体类@TableIdtype属性;
  • table-prefix:统一设置表名前缀(如table-prefix: sys_,实体类User对应表sys_user);
  • update-strategy:更新策略(NOT_NULL:只更新非空字段;IGNORED:所有字段都更新);
  • insert-strategy:插入策略(NOT_NULL:非空字段才插入;IGNORED:所有字段都插入,包括null)。

策略示例

// 更新时只修改非空字段(配合update-strategy: NOT_NULL)
User user = new User();
user.setId(1L);
user.setUsername("新名字"); // 只更新username,其他字段不变
userService.updateById(user);

三、元对象处理器:实现自动填充

元对象处理器(MetaObjectHandler)配合@TableField(fill = ...)实现字段自动填充(如创建时间、更新时间)。

3.1 实现元对象处理器

package com.example.mp.handler;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;@Component // 注册为Spring组件
public class MyMetaObjectHandler implements MetaObjectHandler {// 插入时自动填充@Overridepublic void insertFill(MetaObject metaObject) {// 填充createTime(字段名需与实体类一致)this.strictInsertFill(metaObject, "createTime", // 实体类字段名LocalDateTime.class, LocalDateTime.now() // 填充值);// 填充updateTime(插入时也需设置)this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}// 更新时自动填充@Overridepublic void updateFill(MetaObject metaObject) {// 填充updateTimethis.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}
}

3.2 使用自动填充

在实体类中通过@TableField(fill)指定填充时机:

@Data
@TableName("sys_user")
public class User {@TableId(type = IdType.ASSIGN_ID)private Long id;private String username;// 插入时填充@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 插入和更新时填充@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;
}

效果

  • 调用userService.save(user)时,createTimeupdateTime自动设为当前时间;
  • 调用userService.updateById(user)时,updateTime自动更新为当前时间。

四、插件配置:增强MP功能

MyBatisPlus通过插件机制提供分页、乐观锁等增强功能,需手动配置才能生效。

4.1 分页插件(PaginationInnerInterceptor)

实现分页查询功能,支持MySQL、Oracle等多种数据库。

配置类

package com.example.mp.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件(默认适配MySQL)interceptor.addInnerInterceptor(new PaginationInnerInterceptor());// 若使用Oracle,需指定数据库类型// interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.ORACLE));return interceptor;}
}

使用示例

// 分页查询年龄≥18的用户
Page<User> page = new Page<>(1, 10); // 第1页,每页10条
IPage<User> userPage = userMapper.selectPage(page,new LambdaQueryWrapper<User>().ge(User::getAge, 18)
);
// 分页结果
List<User> records = userPage.getRecords(); // 当前页数据
long total = userPage.getTotal(); // 总条数

4.2 乐观锁插件(OptimisticLockerInnerInterceptor)

配合@Version注解实现乐观锁功能。

配置类

@Configuration
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor());// 添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}
}

使用示例

// 乐观锁更新
User user = userService.getById(1L); // 查询用户(获取当前version=1)
user.setUsername("新名字");
boolean success = userService.updateById(user); 
// SQL:UPDATE sys_user SET username = ?, version = 2 WHERE id = 1 AND version = 1

4.3 防全表更新插件(BlockAttackInnerInterceptor)

禁止全表更新/删除操作(无WHERE条件),防止误操作。

配置类

@Configuration
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加防全表更新插件interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());return interceptor;}
}

效果:执行以下代码会抛出异常:

// 无WHERE条件的更新(被禁止)
userService.update(new UpdateWrapper<User>().set("username", "test")
); 
// 抛出异常:Prohibition of full table update

五、实战场景:注解与配置组合使用

5.1 完整实体类示例

import com.baomidou.mybatisplus.annotation.*;
import com.example.mp.enums.StatusEnum;
import lombok.Data;
import java.time.LocalDateTime;@Data
@TableName("sys_user") // 表名映射
public class User {// 主键:雪花算法生成,对应表字段user_id@TableId(value = "user_id", type = IdType.ASSIGN_ID)private Long id;// 字段映射:实体类name → 表username@TableField(value = "username")private String name;private Integer age;// 枚举类型:数据库存储code值private StatusEnum status;// 插入时自动填充@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 插入和更新时自动填充@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;// 逻辑删除字段@TableLogicprivate Integer isDeleted;// 乐观锁版本字段@Versionprivate Integer version;// 忽略非表字段@TableField(exist = false)private String tempData;
}

5.2 全局配置最佳实践

mybatis-plus:# 实体类包路径(别名)type-aliases-package: com.example.mp.entity# MapperXML路径(若全用注解可省略)mapper-locations: classpath:mapper/*.xmlconfiguration:# 开发环境打印SQLlog-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 关闭二级缓存(分布式环境慎用)cache-enabled: falseglobal-config:db-config:# 全局主键策略(分布式用ASSIGN_ID)id-type: ASSIGN_ID# 表名前缀(统一管理)table-prefix: sys_# 逻辑删除配置logic-delete-field: isDeletedlogic-delete-value: 1logic-not-delete-value: 0# 更新只改非空字段update-strategy: NOT_NULL

六、常见问题与避坑指南

6.1 注解与全局配置冲突

问题:实体类@TableId(type = IdType.AUTO)与全局id-type: ASSIGN_ID冲突。

解决:注解配置优先级高于全局配置,以实体类注解为准。

6.2 自动填充失效

可能原因

  • 未将MetaObjectHandler注册为Spring组件(缺少@Component);
  • 实体类@TableField(fill)的字段名与MetaObjectHandler中填充的字段名不一致;
  • 填充值类型与字段类型不匹配(如LocalDateTime vs Date)。

6.3 分页查询无数据

可能原因

  • 未配置分页插件(PaginationInnerInterceptor);
  • 数据库类型不匹配(如Oracle需指定DbType.ORACLE);
  • 分页参数错误(页码从1开始,而非0)。

6.4 逻辑删除后查询仍能返回数据

可能原因

  • 自定义SQL未添加AND is_deleted = 0条件;
  • 逻辑删除字段名与全局配置logic-delete-field不一致。

总结

MyBatisPlus的注解与配置是简化数据库操作的核心:

  • 核心注解@TableName@TableId@TableField解决表与实体的映射问题;@TableLogic@Version实现逻辑删除和乐观锁;
  • 全局配置:统一管理主键策略、表前缀等,减少重复注解;
  • 插件配置:分页、乐观锁等功能通过插件快速集成,无需手动编写SQL。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

http://www.xdnf.cn/news/1227979.html

相关文章:

  • Docker 部署与配置 MySQL 5.7
  • 位运算-371.两整数之和-力扣(LeetCode)
  • 解决 InputStream 只能读取一次问题
  • 【多模态】DPO学习笔记
  • [创业之路-528]:技术成熟度曲线如何指导创业与投资?
  • Python爬虫实战:研究mahotas库,构建图像获取及处理系统
  • 【DeepSeek-R1 】分词系统架构解析
  • 社群团购市场选择与开源技术赋能下的下沉市场开拓策略研究——以开源AI智能名片、链动2+1模式与S2B2C商城小程序为例
  • LLM Prompt与开源模型资源(3)如何写一个好的 Prompt
  • 【论文笔记】Multi-Behavior Graph Neural Networks for Recommender System
  • “神威·太湖之光”:科技创新引擎与国家算力基石的崛起之路
  • jenkins从入门到精通-P1—九五小庞
  • 机器学习 —— 决策树
  • 【Linux网络】netstat 的 -anptu 各个参数各自表示什么意思?
  • 波士顿咨询校招面试轮次及应对策略解析
  • 个人电脑部署私有化大语言模型LLM
  • 操作系统-lecture5(线程)
  • Flutter镜像替换
  • LVGL + ESP-Brookesia 在Windows下的编译和运行
  • Flutter基础知识
  • 关于Web前端安全防御CSRF攻防的几点考虑
  • 常用git命令
  • 编译器工作原理的显微镜级拆解
  • 开箱即用的Next.js SSR企业级开发模板
  • 什么是doris
  • Typora v1.10.8 好用的 Markdown 编辑器
  • DreamBoards 借助 DreamHAT+ 雷达插件为 Raspberry Pi 提供 60GHz 毫米波雷达
  • 思途JSP学习 0801
  • 《软件测试与质量控制》实验报告一 测试用例设计
  • 逻辑回归参数调优实战指南