告别重复编码:从原生MyBatis无缝迁移到MyBatis-Plus的实战指南
你是否还在手写大量重复的CRUD SQL?是否为分页查询的繁琐实现而头疼?本文将带你一步到位解决这些问题,通过实战案例展示如何将原生MyBatis项目平滑迁移到MyBatis-Plus,让开发效率提升300%。读完本文,你将掌握依赖替换、代码改造、高级功能应用的完整流程,并学会避迁移过程中的常见 pitfalls。
为什么选择MyBatis-Plus?
MyBatis-Plus(简称MP)是一个MyBatis的增强工具包,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。其核心优势包括:
- 无侵入:引入MP不会对现有MyBatis架构产生任何影响
- 通用CRUD操作:内置通用Mapper、通用Service,无需编写SQL即可完成单表操作
- 强大的条件构造器:支持Lambda风格API,轻松构建复杂查询条件
- 内置分页插件:物理分页无需手动编写limit语句
- 多种主键策略:支持分布式唯一ID生成器,完美解决主键问题
官方文档:README.md
迁移准备:环境与依赖配置
1. 移除原生MyBatis依赖
在迁移前,首先需要从项目中移除原生MyBatis相关依赖,避免版本冲突。
2. 添加MyBatis-Plus依赖
根据你的Spring Boot版本选择合适的starter:
Spring Boot 2.x
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>Latest Version</version>
</dependency>
Spring Boot 3.x
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>Latest Version</version>
</dependency>
Spring Boot 4.x
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
<version>Latest Version</version>
</dependency>
依赖配置详情:README-zh.md
核心迁移步骤
1. 配置类改造
将原有的MyBatis配置类替换为MyBatis-Plus的配置类,主要变化是使用MybatisConfiguration替代MyBatis原生的Configuration:
@Configuration
@MapperScan("com.example.mapper")
public class MyBatisPlusConfig {
@Bean
public MybatisConfiguration mybatisConfiguration() {
return new MybatisConfiguration();
}
}
MyBatis-Plus核心配置类:mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisConfiguration.java
2. Mapper接口改造
最关键的一步是让你的Mapper接口继承MP提供的BaseMapper,从而获得内置的CRUD方法:
原生MyBatis Mapper:
public interface UserMapper {
User selectById(Long id);
int insert(User user);
int updateById(User user);
int deleteById(Long id);
List<User> selectList();
}
改造为MyBatis-Plus Mapper:
public interface UserMapper extends BaseMapper<User> {
// 继承后无需编写基本CRUD方法
// 保留自定义的复杂查询方法
}
BaseMapper接口提供的方法包括:
- selectById(id):根据ID查询
- selectList(queryWrapper):条件查询
- insert(entity):插入
- updateById(entity):根据ID更新
- deleteById(id):根据ID删除
- 以及更多批量操作方法...
Mapper接口处理逻辑:mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/MybatisMapperRegistry.java
3. 实体类注解改造
使用MP的注解替换XML配置或原生MyBatis注解,主要注解包括:
@Data
@TableName("t_user") // 指定表名
public class User {
@TableId(type = IdType.AUTO) // 主键策略
private Long id;
@TableField("username") // 指定字段名
private String name;
private Integer age;
@TableField(fill = FieldFill.INSERT) // 自动填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic // 逻辑删除
private Integer deleted;
}
注解定义:mybatis-plus-annotation/src/main/java/com/baomidou/mybatisplus/annotation/
4. Service层改造
Service层同样可以通过继承IService接口获得更强大的批量操作能力:
public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
通过ServiceImpl提供的方法,可以轻松实现:
// 批量插入
boolean saveBatch(Collection<User> entityList);
// 批量更新
boolean updateBatchById(Collection<User> entityList);
// 分页查询
IPage<User> page(IPage<User> page, QueryWrapper<User> queryWrapper);
查询方式优化
1. 条件构造器替代XML/SQL注解
原生MyBatis方式:
<select id="selectByCondition" resultType="User">
SELECT * FROM t_user
WHERE age > #{age}
AND username LIKE CONCAT('%', #{name}, '%')
ORDER BY create_time DESC
</select>
MyBatis-Plus条件构造器:
List<User> userList = userMapper.selectList(new QueryWrapper<User>()
.gt("age", 18)
.like("username", "张")
.orderByDesc("create_time")
);
更安全的Lambda条件构造器:
List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>()
.gt(User::getAge, 18)
.like(User::getName, "张")
.orderByDesc(User::getCreateTime)
);
条件构造器实现:mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/conditions/
2. 分页查询简化
原生MyBatis分页:
<select id="selectPage" resultType="User">
SELECT * FROM t_user
LIMIT #{pageNum}, #{pageSize}
</select>
MyBatis-Plus分页:
// 配置分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
// 使用分页
IPage<User> page = new Page<>(1, 10);
IPage<User> userPage = userMapper.selectPage(page, new QueryWrapper<User>().gt("age", 18));
List<User> records = userPage.getRecords(); // 数据列表
long total = userPage.getTotal(); // 总条数
long pages = userPage.getPages(); // 总页数
高级特性应用
1. 自动填充功能
实现元对象处理器接口,配置字段自动填充:
@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());
}
}
元对象处理器接口:mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/handlers/MetaObjectHandler.java
2. 逻辑删除
通过@TableLogic注解实现逻辑删除,而非物理删除:
@TableLogic
private Integer deleted;
// 配置逻辑删除值
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
使用逻辑删除后,调用deleteById方法实际执行的是更新操作:
UPDATE t_user SET deleted=1 WHERE id=? AND deleted=0
逻辑删除注解:mybatis-plus-annotation/src/main/java/com/baomidou/mybatisplus/annotation/TableLogic.java
3. 枚举处理器
使用MP的枚举处理器,简化枚举类型的数据库存储:
public enum GenderEnum implements IEnum<Integer> {
MALE(1, "男"),
FEMALE(0, "女");
private final int value;
private final String desc;
GenderEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
@Override
public Integer getValue() {
return value;
}
}
// 实体类中使用
@TableField("gender")
private GenderEnum gender;
枚举接口定义:mybatis-plus-annotation/src/main/java/com/baomidou/mybatisplus/annotation/IEnum.java
迁移常见问题及解决方案
1. 方法名冲突
问题:自定义方法与BaseMapper中的方法名冲突
解决方案:重命名自定义方法或使用@SqlParser(filter = true)注解排除
2. 分页插件不生效
问题:分页查询返回全部数据而非分页结果
解决方案:确保正确配置了分页插件并使用MP提供的Page对象
3. 条件构造器字段名错误
问题:使用字符串形式的条件构造器时字段名拼写错误
解决方案:改用Lambda条件构造器,编译期检查字段名正确性
4. 枚举类型处理异常
问题:枚举类型无法正确转换
解决方案:确保枚举类实现IEnum接口或正确配置枚举处理器
迁移效果对比
| 功能 | 原生MyBatis | MyBatis-Plus | 代码量减少 |
|---|---|---|---|
| 单表CRUD | 需要编写XML/SQL | 继承BaseMapper即可 | 90% |
| 条件查询 | 编写动态SQL | 条件构造器链式调用 | 70% |
| 分页查询 | 手动编写LIMIT | 分页插件+Page对象 | 80% |
| 批量操作 | 手动编写循环 | saveBatch/updateBatch | 85% |
总结与展望
通过本文介绍的迁移步骤,你已经掌握了从原生MyBatis迁移到MyBatis-Plus的核心技巧。迁移后,你将获得:
- 大幅减少重复代码,专注业务逻辑
- 提高开发效率,缩短项目周期
- 增强代码可维护性和可读性
- 获得丰富的高级特性支持
MyBatis-Plus的生态还在不断发展,更多强大功能如代码生成器、多租户插件等等待你去探索。建议在迁移完成后,逐步深入学习这些高级特性,进一步提升开发效率。
代码生成器模块:mybatis-plus-generator/
提示:迁移过程建议分模块进行,先从非核心业务模块开始,验证无误后再迁移核心模块,确保系统稳定过渡。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考






