MyBatis-Plus

Mybatis-Plus

在学习微服务之前,我们再次重温MybatisPlus的内容

个人理解,MybatisPlus提供了非常简便的接口以供快速开发单表的增删改查,所以非常契合微服务架构

条件构造器

尤其是在使用体验和对SQL语句的封装程度上,Mybatis-Plus的Wrapper机制确实与EF Core的LINQ查询有异曲同工之妙,使得两者的调用方式在某些场景下显得非常相似

Mybatis-Plus的Wrapper机制,特别是其对Lambda表达式的支持,确实在很大程度上提供了与EF Core的LINQ查询相似的、面向对象的、流式化的SQL构建体验,极大地提升了开发效率


QueryWrapper&UpdateWrapper

当单纯的使用where作为条件拼接时,QueryWrapper可以完美的替代UpdateWrapper

在默认设置的更新策略下Redis(NOT_NULL),是不可以将数据库字段更新为空值的,但使用UpdateWrapper的set方法可以针对字段更新,那么也就可以将指定字段更新为null,这是 UpdateWrapper 的一个重要优势

UpdateWrapper提供了setSql()方法,允许你在SET子句中直接写入SQL片段,这对于实现column = column + 1(自增)、update_time = NOW()(更新时间戳)等操作非常有用


整合

使用wrapper作为where的条件是正确思路,但直接将一些select语句写在service层又不符合企业规范

所以可以将条件的构建交给mybatisplus接管,使用wrapper构建,其他的sql语句仍然写在mapper.xml中

需要注意的是,在mapper层给mapper.xml传wrapper时,我们需要将wrapper参数加上 Param注解,且注解的值必须为ew

或者调用Constants.WRAPPER获取常量


哑巴“mapper”

理想的“哑巴”Mapper:

如果 Mapper 层是绝对的“哑巴”,它应该只知道如何将 User 实体对象映射到 user 表,并提供最基本的 CRUD 操作(insert(User)、update(User)、selectById(id)、deleteById(id))。

它的方法签名和 XML 定义应该严格对应数据库的单表操作,不涉及任何业务概念上的“视图”或“聚合”。

在这种理想情况下,任何涉及多表联查、复杂聚合、或者需要特定字段组合的“业务视图”,都应该由 Service 层通过调用多个 Mapper 的单表方法,然后在内存中进行数据组装和处理。

Mybatis 的现实与优势:

Mybatis 的核心优势就是它能够让你直接编写 SQL。这意味着你可以利用数据库的强大能力来执行复杂的 JOIN、子查询、聚合函数、窗口函数等。

如果 Service 层需要一个“用户及其所有订单”的视图,让数据库通过一个 JOIN 查询一次性返回,通常比 Service 层先查用户,再循环查每个用户的订单(N+1 问题),或者查所有用户和所有订单然后在内存中匹配,要高效得多。

Mybatis 的 resultMap 机制也使得将复杂的 JOIN 结果直接映射到复杂的 DTO/VO 对象变得非常方便,省去了 Service 层手动组装的繁琐。

在 Mybatis 的世界里,我们确实是利用了它方便编写 SQL 的特性,在 Mapper 层(特别是 XML 文件中)定义了许多针对 Service 层特定业务需求而定制的“抽象视图”或“聚合查询”

这是一种务实且高效的架构选择,它在一定程度上“牺牲”了 Mapper 层的绝对“哑巴”特性,以换取更优的性能、更简洁的 Service 层代码(无需手动组装复杂对象),以及更灵活的 SQL 控制能力。这种折中在 Mybatis 社区中是普遍接受的最佳实践。


MybatisPlus的最佳实践

在微服务架构下,Mybatis-Plus 和 Mybatis 并非互斥,而是相辅相成的强大工具。理解它们的优势与适用场景,并遵循清晰的服务边界原则,是构建高效、可维护系统的关键。

1. Mybatis (XML) 最佳实践:复杂查询与性能优化

在服务内部,当面临需要高性能、复杂数据聚合的查询场景时,我们可以在 Mybatis 的 XML Mapper 中编写定制化的 SQL。

  • 妥协“哑巴原则”: 在这种特定场景下,为了追求极致的性能和灵活性,我们可以适度偏离严格的“哑巴原则”(即 SQL 仅负责简单的 CRUD 映射)。
  • 采用“抽象视图原则”: 即在 XML 中编写复杂的 SQL(如多表 JOIN、子查询、聚合函数、窗口函数等),以构建针对特定业务需求的“数据视图”。
  • 优势: 这种方式能够充分利用数据库的优化能力,实现高性能的复杂查询,减少应用层的内存组装和网络往返。对于服务内部的复杂报表、统计或特定业务视图而言,其性能优势是显著的。
  • 局限性: 虽然可能降低 SQL 的通用复用性,因为这些 SQL 通常是为特定业务场景量身定制的。
  • 重要前提: 此实践仅限于服务内部的数据操作。

2. Mybatis-Plus 最佳实践:单表操作与动态条件

Mybatis-Plus 在微服务架构中展现出巨大优势,尤其适用于处理服务内部的单表 CRUD (增删改查) 操作。

  • 简化单表操作: Mybatis-Plus 提供了大量开箱即用的通用方法,极大地简化了单表操作的开发工作,减少了大量的样板代码。这与微服务中每个服务通常聚焦于其核心数据模型的特点高度契合。
  • 强大的 Wrapper 机制: 其核心亮点在于强大的 Wrapper 机制。通过 Wrapper,我们可以在 Java 代码中灵活、类型安全地拼接各种动态的 WHERE 条件、排序、分组等,以满足不同业务场景下对单表数据的查询需求。
  • 优势: 这使得业务逻辑层能够根据运行时参数动态构建查询,而无需为每种条件组合编写独立的 SQL,提高了开发效率和代码可维护性。

3. 核心准则:服务边界与数据所有权

Mybatis-Plus 和 Mybatis 的协同使用,应严格遵循微服务架构的核心原则——服务边界与数据所有权

  • 黄金准则: 同一服务内的多张表应该 JOIN,跨服务的表不应该 JOIN!
  • 服务内 JOIN 的合理性:
    • 服务内部的表通常属于同一个业务领域,共同构成该服务的数据模型。
    • 在同一个数据库实例内进行 JOIN 操作,可以保证事务一致性,并利用数据库的优化能力,实现高效的数据聚合。
    • 这符合服务内部数据内聚的原则。
  • 跨服务 JOIN 的危害:
    • 打破封装性: 直接跨服务 JOIN 数据库表会严重破坏服务的封装性,侵入其他服务的内部实现细节。
    • 紧密耦合: 导致服务间紧密耦合,一旦被 JOIN 的服务修改了数据库结构,依赖方将立即受影响,阻碍服务的独立部署、独立演进和弹性伸缩。
    • 分布式事务复杂性: 跨库 JOIN 无法在一个本地事务中完成,若涉及数据一致性,将引入复杂的分布式事务问题。


MyBatis-Plus
http://blog.170827.xyz/2025/06/04/MyBatis-Plus/
作者
XIAOBAI
发布于
2025年6月4日
许可协议