MyBatis-Plus 全景对比 MyBatis:核心进步 + 实战语法速查表
一、核心定位与本质关系
MyBatis-Plus(简称 MP)是基于 MyBatis 只做增强、不做修改的开源持久层增强框架,完美兼容原生 MyBatis 所有语法、配置与特性,无需废弃原有 MyBatis 代码即可无缝升级。
二者核心区别:
原生 MyBatis:轻量化 SQL 映射框架,自由度极高,所有 CRUD、条件拼接、分页、主键策略均需手动实现,重复代码多、开发效率低。
MyBatis-Plus:保留 MyBatis 灵活特性的同时,封装通用能力、标准化开发规范,零 SQL 实现单表全量 CRUD,解决原生框架冗余、不统一、需插件适配的痛点,是 SpringBoot 项目主流标配。
二、全景维度对比:MP 相比 MyBatis 的核心进步
从开发效率、功能能力、工程规范、性能安全性四大维度,全方位拆解 MP 的迭代升级点,覆盖日常开发所有场景。
1. 基础 CRUD:彻底消灭重复 XML/SQL
对比维度 | 原生 MyBatis | MyBatis-Plus | MP 核心进步 |
|---|---|---|---|
单表 CRUD | 手动编写 Mapper 接口方法、XML SQL 语句,增删改查全量手写 | Mapper 继承 | 省去 80% 单表基础代码,杜绝重复编码失误 |
参数映射 | 手动传参、绑定字段,易出现参数名写错、类型不匹配问题 | 自动 ORM 映射,驼峰字段自动匹配数据库下划线字段 | 简化参数绑定,降低映射报错概率 |
主键生成 | 无内置策略,需手动编码或自定义配置主键自增、UUID 等规则 | 内置雪花算法、自增、UUID、ASSIGN_ID 等主流主键策略,注解一键配置 | 统一主键规范,适配分布式场景 |
2. 条件查询:告别硬编码 SQL,实现链式优雅查询
对比维度 | 原生 MyBatis | MyBatis-Plus | MP 核心进步 |
|---|---|---|---|
条件拼接 | XML 中写 | 内置 | 无需手写动态 SQL,代码简洁易维护 |
字段容错 | 硬写字段名,拼写错误仅运行时报错,无编译校验 | Lambda 构造器通过实体属性引用,编译期校验字段合法性 | 提前规避字段拼写错误,减少线上 Bug |
SQL 注入 | 手动拼接字符串易引发 SQL 注入风险 | 所有条件构造器自动参数预编译,内置防 SQL 注入机制 | 提升代码安全性,无需手动处理防注入 |
3. 高级功能:原生缺失的企业级能力
对比维度 | 原生 MyBatis | MyBatis-Plus | MP 核心进步 |
|---|---|---|---|
分页功能 | 无内置分页,需手写 LIMIT、COUNT 语句,或引入 PageHelper 第三方插件,配置繁琐 | 内置分页拦截器,一行配置开启物理分页,自动封装分页总数、页码、数据列表 | 开箱即用,分页逻辑标准化,无需额外适配 |
逻辑删除 | 需手动修改 DELETE 语句为 UPDATE,统一删除状态,代码分散不统一 |
| 全局统一软删除规范,业务无侵入 |
自动填充 | 新增/修改时手动 set 创建时间、更新时间、创建人、更新人,重复代码多 | 通过 | 解放重复赋值代码,统一基础字段填充规则 |
代码生成 | 无内置生成器,需依赖第三方工具,格式不统一 | 内置代码生成器,一键生成 Entity、Mapper、Service、Controller、DTO 全套代码 | 标准化项目代码结构,大幅提升新项目搭建效率 |
乐观锁 | 需手动实现版本号比对、更新逻辑,自定义拦截规则 | 内置乐观锁插件, | 极简实现并发更新控制,适配高并发场景 |
4. 工程与性能:更适配企业级开发
规范统一:原生 MyBatis 开发自由度过高,团队代码风格参差不齐;MP 基于约定大于配置,统一 CRUD、分页、删除、填充规范,便于团队维护。
性能无损:MP 所有增强能力均基于编译期、拦截器实现,无运行时性能损耗,和原生 MyBatis 执行效率一致。
兼容性极强:不影响原生 MyBatis 自定义 SQL、多表关联、复杂查询,复杂场景可继续手写 XML,简单场景用 MP 通用方法,兼顾效率与灵活性。
监控友好:支持 SQL 日志打印、性能分析插件,可直观查看执行 SQL、耗时,便于问题排查。
三、MyBatis-Plus 高频语法速查表(开发必备)
整理项目中95% 高频使用的 MP 语法、注解、CRUD 方法、条件构造器,直接复制即用,无需重复查文档。
1. 核心实体注解速查
注解 | 作用场景 | 使用示例 |
|---|---|---|
| 实体类与数据库表名不匹配时指定表名 |
|
| 指定主键字段、主键生成策略 |
|
| 指定非主键字段、自动填充、字段忽略 |
|
| 标识逻辑删除字段 |
|
| 乐观锁版本号字段 |
|
| 标识非数据库字段(临时字段) |
|
2. BaseMapper 通用 CRUD 方法速查
Mapper 接口继承BaseMapper<实体类>后直接使用,无需实现。
// 新增 int insert(T entity); // 根据ID删除 int deleteById(Serializable id); // 根据条件删除 int delete(@Param("ew") Wrapper<T> queryWrapper); // 根据ID修改 int updateById(T entity); // 根据条件修改 int update(T entity, @Param("ew") Wrapper<T> updateWrapper); // 根据ID查询 T selectById(Serializable id); // 根据条件查询单条 T selectOne(Wrapper<T> queryWrapper); // 根据条件查询列表 List<T> selectList(Wrapper<T> queryWrapper); // 分页查询 Page<T> selectPage(Page<T> page, Wrapper<T> queryWrapper); // 查询总记录数 Long selectCount(Wrapper<T> queryWrapper);3. 链式条件构造器速查(Lambda 优先,无编译报错)
基础查询条件
// 1. 等值、不等值、范围查询 LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(User::getUsername, "张三") // 等于 .ne(User::getStatus, 0) // 不等于 .gt(User::getAge, 18) // 大于 .lt(User::getAge, 60) // 小于 .ge(User::getCreateTime, startTime) // 大于等于 .le(User::getCreateTime, endTime); // 小于等于 // 2. 模糊查询 wrapper.like(User::getUsername, "张") // 包含 .likeLeft(User::getPhone, "138") // 左模糊 .likeRight(User::getPhone, "99") // 右模糊 // 3. 空值、包含查询 wrapper.isNull(User::getEmail) // 为空 .isNotNull(User::getNickName) // 不为空 .in(User::getStatus, 1,2) // 包含指定值 .notIn(User::getType, 3,4); // 不包含指定值 // 4. 排序、去重 wrapper.orderByAsc(User::getAge) // 升序 .orderByDesc(User::getCreateTime) // 降序 .distinct();条件更新(无需全字段赋值)
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>(); // 只更新指定字段,根据条件批量修改 updateWrapper.eq(User::getDeptId, 100) .set(User::getStatus, 1) .set(User::getUpdateTime, LocalDateTime.now()); userMapper.update(null, updateWrapper);4. 分页语法速查(最简配置+使用)
第一步:配置分页拦截器(全局一次配置)
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 开启物理分页 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }第二步:业务代码使用
// 参数:当前页、每页条数 Page<User> page = new Page<>(1, 10); // 分页查询,自动封装总页数、总条数、数据列表 Page<User> userPage = userMapper.selectPage(page, wrapper);5. Service 层常用封装方法
Service 继承ServiceImpl<UserMapper, User>后使用,比 Mapper 更适配业务层
// 新增/修改 save(T entity) updateById(T entity) saveOrUpdate(T entity) // 存在则更新,不存在则新增 // 批量操作 batchInsert(List<T> list) batchUpdate(List<T> list) // 查询 getById(id) list(Wrapper) page(Page, Wrapper)四、MP 开发避坑要点(核心注意事项)
仅单表优先用 MP:多表关联、复杂子查询、特殊 SQL 场景,建议手写原生 XML SQL,避免条件构造器过度嵌套导致可读性变差。
Lambda 构造器杜绝硬写字段名:优先使用LambdaQueryWrapper,避免字符串字段名引发编译不校验问题。
逻辑删除需全局配置:开启逻辑删除后,MP 会自动过滤已删除数据,如需查询已删除数据,需手动关闭过滤规则。
分页必须配置拦截器:未配置分页拦截器会导致分页失效,仅查询全量数据,不会自动分页。
继承场景开启 super 校验:实体类继承父类时,字段填充、查询需保证父类字段可被 MP 扫描识别。
五、最终选型总结
1.纯 MyBatis 适用场景:老旧项目维护、极复杂多表 SQL、对框架轻量化极致要求、无快速开发需求的传统项目。
2.MyBatis-Plus 适用场景(99% 新项目):SpringBoot 新项目、CRUD 业务量大、追求开发效率、需要统一工程规范、分布式项目、需要逻辑删除、自动填充、分页等企业级能力的场景。
MP 并非替代 MyBatis,而是赋能增强,兼顾原生灵活性与高效开发能力,是目前 Java 后端持久层开发的最优解决方案。