MyBatis-Plus 三种数据库操作方式详解 + 常用方法大全

MyBatis-Plus 三种数据库操作方式详解 + 常用方法大全

在 Java 开发中,MyBatis-Plus(简称 MP)作为 MyBatis 的增强工具,极大简化了数据库操作。MP 提供了多种数据库操作方式,适配不同业务场景,掌握其核心用法能大幅提升开发效率。本文将详细拆解 MP 三种核心操作方式的区别、适用场景,并整理常用方法合集,助力开发者快速上手。

一、核心概念:三种操作方式总览

MP 的数据库操作本质是对 MyBatis 的封装,三种核心方式分别对应不同的使用层级,从简洁到灵活逐步递进:

  • this.*** 方式 :基于 MP 提供的 ServiceImpl 基类,直接调用封装好的 CRUD 方法,极简高效。
  • this.baseMapper().*** 方式:通过 Service 访问对应的 Mapper 对象,支持自定义 SQL 和复杂查询,兼顾灵活与性能。
  • service.getBaseMapper().*** 方式跨 Service 获取其他实体的 Mapper,实现跨表/跨模块操作,适用于聚合统计场景。

二、三种操作方式详细解析

2.1 this.*** 方式:极简 CRUD 首选

核心定义

Service 层接口继承 IService<T>,实现类继承 ServiceImpl<Mapper, Entity> 后,可直接通过 this 调用基类封装的 CRUD 方法。

核心特点
  • 无需手动编写 Mapper 方法,开箱即用。
  • 内置参数校验、异常处理和事务支持(需配合 @Transactional)。
  • 支持 Lambda 条件查询,类型安全,避免字段名硬编码。
  • 代码简洁可读性强,开发效率最高。
常用方法合集
java 复制代码
// 1. 查询操作
this.getById(id); // 根据 ID 单个查询
this.listByIds(Collections.singletonList(id)); // 批量查询(传入 ID 列表)
this.list(); // 查询所有记录
this.count(); // 统计总记录数
this.getOne(new LambdaQueryChainWrapper<>(lambdaQuery()).eq(Entity::getId, id)); // 条件查询单个(避免返回多个报错)
this.lambdaQuery()
    .eq(Entity::getStatus, 1)
    .ge(Entity::createTime, LocalDateTime.now().minusDays(7))
    .list(); // Lambda 多条件查询
this.page(new Page<>(1, 10), lambdaQuery().eq(Entity::type, 2)); // 分页查询

// 2. 新增/修改操作
this.save(entity); // 单条新增
this.saveBatch(Collections.singletonList(entity), 100); // 批量新增(批量大小 100)
this.saveOrUpdate(entity); // 新增或更新(存在 ID 则更新,否则新增)
this.saveOrUpdateBatch(entities, 100); // 批量新增或更新
this.updateById(entity); // 根据 ID 单条更新
this.lambdaUpdate()
    .set(Entity::getStatus, 0)
    .eq(Entity::id, id)
    .update(); // Lambda 条件更新
this.updateBatchById(entities, 100); // 批量更新(需实体含 ID)

// 3. 删除操作
this.removeById(id); // 根据 ID 单条删除
this.removeByIds(Collections.singletonList(id)); // 批量删除(传入 ID 列表)
this.lambdaRemove()
    .eq(Entity::expireTime, LocalDateTime.now())
    .remove(); // Lambda 条件删除
适用场景
  • 单表基本 CRUD 操作(新增、查询、更新、删除)。
  • 简单条件查询(无复杂联表、聚合需求)。
  • 批量数据处理(批量新增/更新/删除)。
  • 业务逻辑简单,追求开发效率的场景。

2.2 this.baseMapper().*** 方式:复杂查询必备

核心定义

ServiceImpl 基类内置了 baseMapper 属性,对应当前 Service 关联的 Mapper 接口。通过 this.baseMapper() 可直接调用 Mapper 中的方法,包括 MP 自动生成的方法和自定义 SQL 方法。

核心特点
  • 更接近原生 MyBatis,支持自定义 XML/注解 SQL。
  • 可使用 QueryWrapper/LambdaQueryWrapper 构建复杂条件。
  • 支持动态 SQL、结果映射、联表查询等 MyBatis 高级特性。
  • 性能更优,减少中间层封装开销,适合性能敏感场景。
常用方法合集
java 复制代码
// 1. 基础查询
this.baseMapper().selectById(id); // 根据 ID 查询
this.baseMapper().selectBatchIds(Collections.singletonList(id)); // 批量查询
this.baseMapper().selectList(new LambdaQueryWrapper<Entity>().eq(Entity::name, "test")); // 条件查询列表
this.baseMapper().selectCount(new LambdaQueryWrapper<Entity>().eq(Entity::status, 1)); // 条件统计
this.baseMapper().selectOne(new LambdaQueryWrapper<Entity>().eq(Entity::id, id)); // 条件查询单个
this.baseMapper().selectPage(new Page<>(1, 10), new LambdaQueryWrapper<Entity>().eq(Entity::type, 2)); // 分页查询

// 2. 新增/修改/删除
this.baseMapper().insert(entity); // 单条新增
this.baseMapper().updateById(entity); // 根据 ID 更新
this.baseMapper().update(
    new LambdaUpdateWrapper<Entity>()
        .set(Entity::status, 0)
        .eq(Entity::id, id)
); // 条件更新
this.baseMapper().deleteById(id); // 根据 ID 删除
this.baseMapper().delete(new LambdaQueryWrapper<Entity>().eq(Entity::expireTime, LocalDateTime.now())); // 条件删除

// 3. 自定义方法(需在 Mapper 接口中定义)
this.baseMapper().selectByCustomCondition(param); // 自定义条件查询(如联表、复杂过滤)
this.baseMapper().customUpdate(param); // 自定义更新(如批量更新特定字段)
适用场景
  • 需要自定义 SQL(联表查询、复杂过滤、存储过程调用)。
  • 复杂条件查询(多字段组合、动态条件拼接)。
  • 性能敏感场景(如高频查询、大数据量操作)。
  • 需使用 MyBatis 高级特性(结果映射、动态 SQL、一级缓存优化)。

2.3 service.getBaseMapper().*** 方式:跨模块聚合专用

核心定义

通过注入其他 Service 实例,调用其 getBaseMapper() 方法,直接操作其他实体表的 Mapper,实现跨表/跨模块数据操作。

核心特点
  • 跨 Service 直接操作数据库,绕过 Service 层业务逻辑。
  • 适合多表聚合查询、跨模块统计分析。
  • 灵活性极高,但需谨慎使用,避免破坏业务封装。
  • 事务管理需手动控制,否则可能导致数据一致性问题。
常用方法合集
java 复制代码
// 注入其他 Service(如 PictureService)
@Autowired
private PictureService pictureService;

// 1. 跨表查询
List<Picture> pictureList = pictureService.getBaseMapper().selectList(
    new LambdaQueryWrapper<Picture>()
        .eq(Picture::relatedId, entityId)
        .eq(Picture::status, 1)
); // 查询关联图片列表

// 2. 聚合统计
List<Map<String, Object>> categoryCount = pictureService.getBaseMapper().selectMaps(
    new QueryWrapper<Picture>()
        .select("category", "count(*) as count")
        .groupBy("category")
        .having("count(*) > 10")
); // 统计各分类图片数量(大于 10 条)

// 3. 跨表分页
IPage<Map<String, Object>> pageResult = pictureService.getBaseMapper().selectMapsPage(
    new Page<>(1, 10),
    new QueryWrapper<Picture>()
        .eq("related_type", "article")
        .orderByDesc("create_time")
); // 分页查询指定类型的关联数据

// 4. 跨表删除(谨慎使用)
pictureService.getBaseMapper().delete(
    new LambdaQueryWrapper<Picture>().eq(Picture::relatedId, entityId)
); // 删除关联的图片数据
适用场景
  • 跨模块数据聚合(如统计多个表的关联数据)。
  • 复杂统计分析(多表分组、聚合函数计算)。
  • 需绕过其他 Service 层复杂业务逻辑,直接操作数据库。
  • 临时数据处理、报表生成等场景。
注意事项
  • 破坏 Service 层封装性,可能导致业务逻辑不一致。
  • 事务需手动管理(如使用 @Transactional(propagation = Propagation.REQUIRED))。
  • 增加代码耦合度,后续维护成本升高。
  • 非必要场景避免使用,优先通过 Service 层调用实现跨模块交互。

三、三种方式核心区别对比表

特性 this.*** 方式 this.baseMapper().*** 方式 service.getBaseMapper().*** 方式
使用范围 当前实体表 当前实体表 其他实体表(跨模块/跨表)
代码简洁性 极高 中等 中等
灵活性 低(仅支持基础操作) 高(支持自定义 SQL) 极高(跨表+自定义 SQL)
性能 中等(多一层封装) 高(接近原生 MyBatis) 高(直接操作 Mapper)
业务封装性 好(遵循 Service 规范) 好(仅操作当前实体) 差(绕过其他 Service 逻辑)
事务支持 自动(继承 Service 事务) 手动(需自行注解) 需手动控制(跨 Service 事务)
适用场景 简单 CRUD、批量操作 复杂查询、性能优化、自定义 SQL 跨表聚合、统计分析、临时数据处理

四、MP 常用方法分类汇总

4.1 查询类(高频)

方法签名 功能描述 所属方式
getById(ID id) 根据 ID 查询单条记录 this.***
listByIds(Collection<? extends ID> ids) 批量查询(ID 列表) this.***
list(Wrapper<T> queryWrapper) 条件查询列表 this.***/baseMapper
lambdaQuery().eq(...) Lambda 条件查询(类型安全) this.***
selectPage(IPage<T> page, Wrapper<T> queryWrapper) 分页查询 baseMapper/跨 Service
selectCount(Wrapper<T> queryWrapper) 条件统计记录数 baseMapper/跨 Service
selectMaps(Wrapper<T> queryWrapper) 条件查询返回 Map 列表(无需实体) baseMapper/跨 Service

4.2 新增/修改类(高频)

方法签名 功能描述 所属方式
save(T entity) 单条新增 this.***
saveBatch(Collection<T> entityList, int batchSize) 批量新增 this.***
saveOrUpdate(T entity) 新增或更新(根据 ID 判断) this.***
updateById(T entity) 根据 ID 更新 三种方式均支持
lambdaUpdate().set(...).eq(...) Lambda 条件更新 this.***
update(Wrapper<T> updateWrapper) 条件更新(非 ID 字段) baseMapper/跨 Service
updateBatchById(Collection<T> entityList, int batchSize) 批量更新 this.***

4.3 删除类(高频)

方法签名 功能描述 所属方式
removeById(ID id) 根据 ID 删除 this.***
removeByIds(Collection<? extends ID> ids) 批量删除(ID 列表) this.***
lambdaRemove().eq(...) Lambda 条件删除 this.***
delete(Wrapper<T> queryWrapper) 条件删除 baseMapper/跨 Service

五、最佳实践建议

  1. 优先使用 this.*** 方式:单表基础 CRUD 场景首选,代码简洁、维护成本低,且内置异常处理和事务支持。
  2. 复杂场景用 this.baseMapper().***:需要自定义 SQL、联表查询或性能优化时,切换到此方式,兼顾灵活性和性能。
  3. 谨慎使用跨 Service 方式:仅在跨表聚合、统计分析等必要场景使用,使用时需注意事务管理和代码耦合问题。
  4. 保持代码一致性 :同一项目中尽量统一操作方式,避免混用导致可读性下降(如统一用 this.*** 处理简单 CRUD,baseMapper 处理复杂查询)。
  5. 善用 Lambda 表达式 :优先使用 LambdaQueryWrapper/LambdaUpdateWrapper,避免字段名硬编码,减少因字段修改导致的 Bug。
  6. 批量操作指定批次大小 :使用 saveBatch/updateBatchById 时,指定合理的批次大小(如 100-500),避免一次性操作过多数据导致数据库压力过大。

总结

MyBatis-Plus 的三种数据库操作方式各有侧重,从极简的 this.*** 到灵活的 baseMapper,再到跨模块的 service.getBaseMapper(),覆盖了从简单 CRUD 到复杂聚合的全场景需求。掌握其核心区别和适用场景,结合常用方法合集,能大幅提升数据库操作效率。

如果本文对你有帮助,欢迎点赞、收藏、转发~ 若需补充特定场景的用法示例(如联表查询、动态 SQL 实战),可在评论区留言!

相关推荐
-Xie-2 小时前
Redis(八)——多线程与单线程
java·数据库·redis
G探险者2 小时前
为什么 VARCHAR(1000) 存不了 1000 个汉字? —— 详解主流数据库“字段长度”的底层差异
数据库·后端·mysql
Albert Tan3 小时前
Oracle EBS R12.2.14 清理FND_LOBS并释放磁盘空间
数据库·oracle
L.EscaRC4 小时前
图数据库Neo4j原理与运用
数据库·oracle·neo4j
知己80804 小时前
docker搭建图数据库neo4j
数据库·docker·neo4j
TDengine (老段)4 小时前
什么是 TDengine IDMP?
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
谅望者4 小时前
数据分析笔记08:Python编程基础-数据类型与变量
数据库·笔记·python·数据分析·概率论
Boilermaker19924 小时前
【MySQL】备份与恢复
数据库·mysql
q***7484 小时前
数据库高安全—openGauss安全整体架构&安全认证
数据库·安全·架构