☰
MyBatis-Plus实战:提升Java开发效率的ORM利器
2026/10/14 9:00:28 网站建设 项目流程

1. MyBatis-Plus初探:为什么选择它?

第一次接触MyBatis-Plus是在2018年接手一个电商后台项目时。当时团队还在用原生MyBatis,每次新增一个简单的CRUD接口都要重复编写大量模板代码,Mapper.xml文件膨胀到难以维护的程度。直到某天架构师扔给我一个GitHub链接:"试试这个,能让你的开发效率提升50%"。这就是我与MyBatis-Plus的初次邂逅。

MyBatis-Plus(简称MP)本质上是对MyBatis的增强工具包,它保留了MyBatis的所有特性,同时通过内置通用Mapper和Service,将开发者从繁琐的SQL编写中解放出来。最直观的感受是:原先需要写20行代码的查询,现在用Wrapper两三行就能搞定。根据我的项目统计,使用MP后DAO层代码量平均减少60%,特别是对于单表操作,几乎可以做到零SQL。

注意:虽然MP能大幅简化开发,但并不意味着要完全替代MyBatis。复杂多表关联查询时,仍然需要手写XML或注解SQL。

2. 环境搭建与基础配置

2.1 项目依赖引入

以Maven项目为例,需要在pom.xml中添加核心依赖。这里特别强调版本选择的重要性——我曾因盲目使用最新版踩过坑。目前(2023年)生产环境推荐使用3.5.3.x稳定版:

<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency>

如果是非Spring Boot项目,需要额外配置MyBatis原生依赖。Spring Boot项目则会自动配置数据源和事务管理器,这也是我推荐Spring Boot用户直接使用starter的原因。

2.2 基础配置项解析

在application.yml中,MP有几个关键配置需要关注:

mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL日志打印 global-config: db-config: id-type: auto # 主键策略 logic-delete-field: deleted # 逻辑删除字段

其中id-type配置让我栽过跟头。当使用MySQL自增主键时设为auto没问题,但如果用UUID或雪花算法,必须改为assign_id。曾经有次线上事故就是因为这个配置错误导致主键冲突。

3. 核心功能实战演示

3.1 实体类与Mapper的魔法

MP最惊艳的功能莫过于通用Mapper。定义一个User实体类:

@Data @TableName("sys_user") // 实际表名映射 public class User { @TableId(type = IdType.AUTO) private Long id; private String username; @TableField("real_name") // 字段映射 private String realName; @TableLogic // 逻辑删除标记 private Integer deleted; }

对应的Mapper接口只需要简单继承:

public interface UserMapper extends BaseMapper<User> { // 无需任何方法定义 }

这时你已经拥有了全套CRUD方法。我常用的几个快捷操作:

  • insert(user):插入记录
  • selectById(1L):按ID查询
  • updateById(user):按ID更新
  • deleteById(1L):按ID删除

3.2 QueryWrapper条件构造器

动态SQL构造是MP的杀手级功能。比如要查询姓"张"的18岁以上用户:

QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like("username", "张") .ge("age", 18) .orderByDesc("create_time"); List<User> users = userMapper.selectList(wrapper);

等效于SQL:

SELECT * FROM sys_user WHERE username LIKE '%张%' AND age >= 18 ORDER BY create_time DESC

踩坑提醒:字段名写错不会编译报错,只会运行时抛出异常。建议使用Lambda写法:

wrapper.like(User::getUsername, "张")

3.3 分页查询的正确姿势

MP的分页需要先配置拦截器:

@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; }

查询示例:

Page<User> page = new Page<>(1, 10); // 当前页, 每页条数 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("department", "研发部"); Page<User> result = userMapper.selectPage(page, wrapper);

注意:MySQL分页在大数据量时存在性能问题,我曾处理过一个500万数据表的优化案例,最终采用last_id分页模式替代传统limit。

4. 高级特性与性能优化

4.1 逻辑删除实现

只需要在实体字段加@TableLogic注解,MP会自动处理删除操作:

@TableLogic private Integer deleted;

执行deleteById()实际会生成:

UPDATE sys_user SET deleted=1 WHERE id=?

查询时自动附加deleted=0条件。这个功能虽然方便,但在关联查询时需要特别注意,我有次就因忽略这个机制导致数据不一致。

4.2 自动填充功能

比如自动填充创建时间:

@TableField(fill = FieldFill.INSERT) private LocalDateTime createTime;

需要实现MetaObjectHandler:

@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); } }

4.3 性能优化建议

  1. 避免N+1查询:使用@TableField(exist = false)标注非表字段,通过@Select注解或XML处理关联查询
  2. 批量操作:使用saveBatch()替代循环单条insert,我测试过万级数据插入,批量方式快8-10倍
  3. 索引提示:在Wrapper中使用hint("idx_name")强制使用特定索引

5. 生产环境踩坑实录

5.1 字段映射的坑

有次上线后发现查询结果全是null,排查半天才发现是同事把@TableField("user_name")写成了@TableField("username"),而数据库实际字段是user_name。现在团队强制要求所有字段显式声明映射。

5.2 版本升级的坑

从3.4.x升级到3.5.x时,Wrapper的or()方法行为发生了变化。原先的:

wrapper.eq("A",1).or().eq("B",2)

生成的SQL从(A=1) OR (B=2)变成了A=1 OR B=2,导致优先级变化。现在我们都改用Lambda写法:

wrapper.and(w -> w.eq("A",1).or().eq("B",2))

5.3 逻辑删除的联表查询

当主表逻辑删除后,如果使用leftJoin关联查询,需要手动添加主表的deleted=0条件,否则会出现"幽灵数据"。这是我们用AOP统一处理的典型场景。

6. 最佳实践总结

经过5个大型项目实践,我们团队沉淀出以下规范:

  1. 目录结构:

    ├── entity ├── mapper │ └── custom // 自定义SQL ├── service │ ├── impl │ └── wrapper // 查询条件封装
  2. 编码规范:

    • 所有查询必须通过Wrapper构建
    • 禁止在业务层直接拼接SQL片段
    • 分页参数必须校验最大值
  3. 扩展建议:

    • 自定义通用方法:通过CustomerSqlInjector扩展
    • 多租户实现:使用TenantLineInnerInterceptor
    • 数据权限:结合@DataScope注解处理

最后分享一个性能检测技巧:在测试环境开启mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl,配合日志级别DEBUG,可以清晰看到每次操作的执行时间和SQL。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询