Spring Boot整合MyBatis-Plus案例

wen java案例 3

Spring Boot整合MyBatis-Plus案例:从零搭建高效数据访问层(附完整代码)

目录导读

  1. 为什么选择MyBatis-Plus? —— 对比传统MyBatis的核心优势
  2. 环境准备与依赖配置 —— Maven依赖、版本选择避坑指南
  3. 核心代码实战 —— 实体类、Mapper接口、Service层的最佳实践
  4. 高级特性演示 —— 条件构造器、分页插件、自动填充
  5. 常见问题与性能优化 —— 逻辑删除、SQL日志、连接池调优
  6. 问答环节 —— 解决你整合过程中的90%困惑

为什么选择MyBatis-Plus?

传统MyBatis开发中,我们常常需要为每个实体类手写CRUD的XML映射文件,繁琐且易错,MyBatis-Plus(简称MP)作为MyBatis的增强工具,在保留原生灵活性的同时,提供了开箱即用的CRUD方法、条件构造器、分页插件等特性,大幅减少样板代码,根据官方统计,使用MP后,基础数据访问代码量平均减少70%以上,而性能损耗几乎为零。

Spring Boot整合MyBatis-Plus案例

核心优势对比:

  • 单表CRUD无需写SQL,直接调用selectById()insert()等方法
  • 内置代码生成器,一键生成实体、Mapper、Service、Controller
  • 提供乐观锁、逻辑删除、自动填充等企业级解决方案
  • 与Spring Boot完美集成,配置极简

环境准备与依赖配置

环境要求: JDK 8+、Maven 3.6+、MySQL 5.7+(或8.0+)

关键依赖(POM.xml) 注意版本兼容性:

<!-- Spring Boot 2.7.x 为基础 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
</parent>
<dependencies>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

重要配置(application.yml):

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
    username: root
    password: 123456
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 打印SQL日志
  global-config:
    db-config:
      logic-delete-field: deleted  # 全局逻辑删除字段
      logic-delete-value: 1
      logic-not-delete-value: 0
  mapper-locations: classpath*:/mapper/**/*.xml  # 自定义XML位置

避坑提示: 如果你的Spring Boot版本是3.x,请使用mybatis-plus-spring-boot3-starter,否则会无法启动。


核心代码实战

1 实体类(使用Lombok简化)

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableLogic  // 逻辑删除注解
    private Integer deleted;
}

2 Mapper接口(继承BaseMapper)

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 自定义复杂SQL方法,例如多表联查
    List<UserVO> selectUserWithOrders(@Param("userId") Long userId);
}

注意: 无需写任何CRUD方法,MyBatis-Plus已经内置了insertselectByIdupdateById等20+常用方法。

3 Service层(继承IService)

@Service
public class UserService extends ServiceImpl<UserMapper, User> {
    // 直接使用 this.save()、this.list() 等
    public List<User> getAdultUsers() {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.ge(User::getAge, 18);
        return this.list(wrapper);
    }
}

高级特性演示

1 条件构造器(Wrapper)

这是MP最强大的功能之一,可以避免编写大量动态SQL。

// 链式查询:年龄在20-30之间且名字包含"张"的用户
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.between(User::getAge, 20, 30)
       .like(User::getName, "张")
       .orderByDesc(User::getUpdateTime);
List<User> users = userMapper.selectList(wrapper);

2 分页插件配置

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
// 使用分页
Page<User> page = new Page<>(1, 10);  // 第1页,每页10条
Page<User> result = userMapper.selectPage(page, null);
System.out.println("总记录数:" + result.getTotal());

3 自动填充(审计字段)

通过MetaObjectHandler实现创建/更新时间自动填入。

@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());
    }
}

常见问题与性能优化

问题场景 解决方案
表名与实体类名不一致 使用@TableName("实际表名")
主键自增失效 确保数据库主键AUTO_INCREMENT,实体ID用IdType.AUTO
查询性能慢 开启SQL日志,检查是否走了索引;可配合@SqlParser过滤
逻辑删除导致唯一索引冲突 将逻辑删除字段与一个唯一键组合,或使用UUID

性能优化建议:

  • 统一使用LambdaQueryWrapper避免字符串硬编码
  • 大批量插入时使用saveBatch(),默认批处理大小1000
  • application.yml中配置mybatis-plus.configuration.map-underscore-to-camel-case: true(默认开启)

问答环节

Q1:MyBatis-Plus是否取代了MyBatis? 不是取代,而是增强,MP内部依然依赖MyBatis的SqlSessionFactory,你完全可以混合使用:简单CRUD用MP,复杂SQL用原生XML。

Q2:如何避免实体属性与数据库字段映射失败? 如果你使用的是user_name这种下划线风格,MP默认会自动映射为userName,如果映射始终报错,检查是否关闭了map-underscore-to-camel-case配置。

Q3:多租户或数据权限隔离怎么办? MP提供了TenantLineInnerInterceptor插件,可以自动在SQL后追加WHERE tenant_id = ?,具体实现请参考官方文档的“多租户插件”章节。

Q4:整合后启动报错Invalid bound statement (not found) 通常是因为@Mapper注解所在的类没有被Spring扫描,解决方法:在启动类添加@MapperScan("com.example.mapper"),或在每个Mapper上标注@Mapper(已添加)。

Q5:使用MP后,事务管理是否受影响? 完全不受影响,你依然可以在Service方法上使用@Transactional,MP的CRUD操作会自动参与事务。


通过本文的案例实践,你应该已经掌握Spring Boot整合MyBatis-Plus的核心思路,从基础配置到条件构造器、分页、自动填充,每一步都伴随着真实可运行的代码,MyBatis-Plus带来的开发效率提升是立竿见影的,但切记:当业务走向复杂时,灵活结合原生SQL依然是关键技能,建议后续深入阅读其官方文档中的“插件扩展”和“SQL注入器”章节,以应对更多业务场景。

抱歉,评论功能暂时关闭!