MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,旨在简化开发、提高效率。它的核心价值在于:通过继承
BaseMapper,无需编写任何 SQL 和 XML 映射文件,即可获得完整的单表 CRUD 能力。
一句话速记:MyBatis-Plus = MyBatis + 瑞士军刀皮肤 + 防删库保险栓。它保留了 MyBatis 的全部灵活性,同时用 Lambda 表达式和自动化能力解决了原生框架的重复劳动问题。
一、快速入门:3 步启动
1.1 引入依赖
xml
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency>
注意:引入 MP 的 starter 后,可以移除原生的
mybatis-spring-boot-starter依赖,避免版本冲突。MP 的 starter 已包含 MyBatis 核心包。
1.2 继承 BaseMapper
java
@Mapper public interface UserMapper extends BaseMapper<User> { // 无需编写任何方法,即可获得完整 CRUD 能力 }
1.3 实体类映射
java
@Data @TableName("user") // 指定表名,类名与表名一致时可省略 public class User { @TableId(type = IdType.AUTO) // 主键策略:数据库自增 private Long id; private String name; private Integer age; private String email; }
二、核心注解速查表
| 注解 | 作用 | 示例 |
|---|---|---|
@TableName | 指定实体类对应的数据库表名 | @TableName("sys_user") |
@TableId | 指定主键字段及生成策略 | @TableId(value = "id", type = IdType.AUTO) |
@TableField | 指定普通字段映射 | @TableField("user_name");@TableField(exist = false)(非表字段) |
@TableLogic | 逻辑删除字段标记 | @TableLogic private Integer deleted; |
@Version | 乐观锁版本号字段 | @Version private Integer version; |
主键策略(IdType)
| 策略 | 说明 |
|---|---|
AUTO | 数据库 ID 自增 |
ASSIGN_ID | 雪花算法生成 Long 型 ID(默认策略) |
INPUT | 用户手动输入 ID |
ASSIGN_UUID | 分配 UUID,主键类型为 String |
三、BaseMapper CRUD 速查
BaseMapper 内置了完整的单表操作 API,无需手动编写 SQL。
| 操作类型 | 方法 | 说明 |
|---|---|---|
| 插入 | int insert(T entity) | 插入一条记录,自动忽略 null 字段 |
| 删除 | int deleteById(Serializable id) | 根据主键删除 |
int deleteBatchIds(Collection<?> idList) | 批量删除 | |
int deleteByMap(Map<String, Object> columnMap) | 根据 Map 条件删除 | |
int delete(Wrapper<T> wrapper) | 根据条件构造器删除 | |
| 更新 | int updateById(T entity) | 根据主键更新,只更新非 null 字段 |
int update(T entity, Wrapper<T> updateWrapper) | 根据条件更新 | |
| 查询 | T selectById(Serializable id) | 根据主键查询 |
List<T> selectBatchIds(Collection<?> idList) | 批量 ID 查询 | |
List<T> selectByMap(Map<String, Object> columnMap) | 根据 Map 条件查询 | |
List<T> selectList(Wrapper<T> queryWrapper) | 条件查询(返回列表) | |
T selectOne(Wrapper<T> queryWrapper) | 条件查询(返回单条) | |
Integer selectCount(Wrapper<T> queryWrapper) | 条件计数 | |
IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper) | 分页查询 |
四、条件构造器(Wrapper)
条件构造器是 MP 最核心的查询工具,通过链式编程动态构建 SQL 条件,避免硬编码字段名和 SQL 注入风险。
4.1 Wrapper 继承体系
text
Wrapper ├── AbstractWrapper │ ├── QueryWrapper // 查询条件封装 │ ├── UpdateWrapper // 更新条件封装 │ └── LambdaQueryWrapper // Lambda 版(推荐) └── LambdaUpdateWrapper // Lambda 版更新(推荐)
4.2 常用条件方法速查表
| 方法 | 说明 | 示例 |
|---|---|---|
eq | 等于 = | .eq("name", "张三") |
ne | 不等于 <> | .ne("age", 20) |
gt | 大于 > | .gt("age", 18) |
ge | 大于等于 >= | .ge("age", 18) |
lt | 小于 < | .lt("age", 65) |
le | 小于等于 <= | .le("age", 65) |
between | BETWEEN ... AND ... | .between("age", 18, 30) |
like | LIKE '%值%' | .like("name", "张") |
likeLeft | LIKE '%值' | .likeLeft("name", "三") |
likeRight | LIKE '值%' | .likeRight("name", "张") |
in | IN ( ... ) | .in("id", Arrays.asList(1,2,3)) |
isNull | IS NULL | .isNull("email") |
isNotNull | IS NOT NULL | .isNotNull("email") |
orderByAsc | ORDER BY ... ASC | .orderByAsc("age") |
orderByDesc | ORDER BY ... DESC | .orderByDesc("create_time") |
select | 指定查询字段 | .select("id", "name", "email") |
set | UPDATE 时设置字段值 | .set("email", "new@mail.com") |
4.3 推荐使用 LambdaWrapper
使用 Lambda 表达式通过方法引用指定字段,可在编译期发现字段名错误,是更安全、更推荐的方式。
java
@Test void testLambdaQueryWrapper() { LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.gt(User::getAge, 20) .like(User::getName, "张") .orderByDesc(User::getAge); List<User> users = userMapper.selectList(wrapper); }
4.4 条件性添加(NULL 值自动跳过)
当查询条件可能为 null 时,传统方式需要大量 if 判断。MP 支持条件性添加,一行解决:
java
// 方法签名:.eq(condition, column, value) // 只有 condition 为 true 时,该条件才会生效 wrapper.eq(status != null, User::getStatus, status) .like(name != null, User::getUsername, name);
4.5 更新条件(UpdateWrapper)
java
@Test void testUpdateWrapper() { // 将指定用户余额减少 200 UpdateWrapper<User> wrapper = new UpdateWrapper<>(); wrapper.setSql("balance = balance - 200") .in("id", Arrays.asList(1L, 2L, 4L)); userMapper.update(null, wrapper); }
五、Service 层封装
MP 对 Service 层也提供了增强。继承IService接口和ServiceImpl实现类,即可获得丰富的业务层方法。
5.1 快速接入
java
// Service 接口 public interface UserService extends IService<User> { // 可添加自定义业务方法 } // Service 实现类 @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { // 无需手动实现,即可使用 IService 的全部方法 }
5.2 IService 常用方法速查
| 类型 | 方法 | 说明 |
|---|---|---|
| 保存 | boolean save(T entity) | 插入一条记录 |
boolean saveBatch(Collection<T> entityList) | 批量插入 | |
| 更新 | boolean updateById(T entity) | 根据 ID 更新 |
boolean update(T entity, Wrapper<T> updateWrapper) | 根据条件更新 | |
boolean updateBatchById(Collection<T> entityList) | 批量更新 | |
| 查询 | T getById(Serializable id) | 根据 ID 查询 |
List<T> list(Wrapper<T> queryWrapper) | 条件查询(列表) | |
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper) | 分页查询 | |
long count(Wrapper<T> queryWrapper) | 条件计数 | |
| 删除 | boolean removeById(Serializable id) | 根据 ID 删除 |
boolean remove(Wrapper<T> queryWrapper) | 根据条件删除 | |
| 链式调用 | lambdaQuery() | Lambda 条件查询 |
lambdaUpdate() | Lambda 条件更新 |
5.3 Service 层 Lambda 链式调用
java
public List<User> queryUserList(String name, Integer status, Integer minBal, Integer maxBal) { return lambdaQuery() .like(name != null, User::getUsername, name) .eq(status != null, User::getStatus, status) .between(minBal != null && maxBal != null, User::getBalance, minBal, maxBal) .list(); }
六、高级特性
6.1 分页插件
配置分页插件后,分页查询如同普通 List 查询一样简单。
java
// 1. 配置分页插件(Spring Boot 配置类) @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } // 2. 使用分页查询 @Test void testPage() { Page<User> page = new Page<>(1, 10); // 第1页,每页10条 LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.ge(User::getAge, 18); Page<User> result = userMapper.selectPage(page, wrapper); List<User> records = result.getRecords(); long total = result.getTotal(); }
6.2 逻辑删除
逻辑删除通过标记字段实现“假删除”,数据不会真正从数据库移除。
java
// 实体类添加逻辑删除字段 @TableLogic private Integer deleted; // 配置文件 mybatis-plus: global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 # 已删除值 logic-not-delete-value: 0 # 未删除值
6.3 自动填充
自动填充用于create_time、update_time等字段,无需手动设置。
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()); this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } }
6.4 乐观锁
通过版本号机制防止并发更新冲突。
java
// 实体类添加版本号字段 @Version private Integer version; // 配置乐观锁插件 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; }
6.5 代码生成器
根据数据库表结构自动生成 Entity、Mapper、Service、Controller 等代码。具体配置可根据官方文档示例结合项目实际进行调整。
6.6 自定义 SQL(Wrapper 复用)
利用 Wrapper 构建 Where 条件,自定义 SQL 的剩余部分。
java
// 1. Mapper 接口 void updateBalanceByIds(@Param("ew") LambdaQueryWrapper<User> wrapper, @Param("amount") int amount); // 2. XML 映射 <update id="updateBalanceByIds"> UPDATE user SET balance = balance - #{amount} ${ew.customSqlSegment} </update> // 3. 调用端 @Test void testCustomSql() { LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.in(User::getId, Arrays.asList(1L, 2L, 4L)); userMapper.updateBalanceByIds(wrapper, 200); }
七、配置速查表
yaml
mybatis-plus: # Mapper XML 文件位置 mapper-locations: classpath*:/mapper/**/*.xml # 实体类别名扫描包 type-aliases-package: com.example.entity configuration: # 驼峰命名自动映射(默认 true) map-underscore-to-camel-case: true # SQL 日志输出(开发环境开启) log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 二级缓存 cache-enabled: false global-config: db-config: # 主键策略:assign_id(雪花算法)/ auto(自增)/ none id-type: assign_id # 逻辑删除字段名 logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 # 更新策略:只更新非空字段 update-strategy: not_null
八、总结
| 功能模块 | 核心要点 |
|---|---|
| BaseMapper | 继承即用,零 SQL 实现单表 CRUD |
| LambdaWrapper | 类型安全的条件构造,编译期校验字段名 |
| IService | Service 层增强,批量操作、链式调用 |
| 分页插件 | 物理分页,一行配置,与普通查询无异 |
| 逻辑删除 | 假删除机制,数据可追溯 |
| 乐观锁 | 版本号防并发冲突 |
| 代码生成器 | 一键生成全套基础代码 |
核心建议:优先使用LambdaQueryWrapper / LambdaUpdateWrapper替代字符串硬编码;复杂查询组合使用 Wrapper + 自定义 SQL;日常 CRUD 直接复用 BaseMapper / IService 即可,省去编写冗余 XML 的重复劳动。MP 让开发者能够将精力聚焦于业务逻辑,而非底层 SQL 的重复劳动。