← 返回文章列表

MyBatis-Plus 实战指南:从零到精通

在日常的 Java 后端开发中,数据库操作是不可避免的核心环节。MyBatis-Plus 作为 MyBatis 的增强工具,在保留原有功能的基础上,提供了更便捷的 CRUD 操作、强大的条件构造器和丰富的插件生态。本文将结合 Spring Boot 4 项目,全面介绍 MyBatis-Plus 的实战应用。

一、引入依赖

在 Spring Boot 4 项目中,添加 MyBatis-Plus 依赖:

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

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.23</version>
</dependency>

二、配置数据源

application.yml 中配置数据库连接:

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8
    username: root
    password: password

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  global-config:
    db-config:
      id-type: assign_id
      logic-delete-field: deleted
      logic-delete-value: 1
      logic-not-delete-value: 0
  mapper-locations: classpath:/mapper/**/*.xml

三、实体类定义

使用注解定义实体类,MyBatis-Plus 会自动映射表结构:

@Data
@TableName("user")
public class User {
    
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    
    private String username;
    
    private String email;
    
    @TableField("phone_number")
    private String phoneNumber;
    
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    
    @TableLogic
    @TableField(select = false)
    private Integer deleted;
    
    @Version
    private Integer version;
}

四、Mapper 接口

继承 BaseMapper 即可获得基础 CRUD 能力:

@Mapper
public interface UserMapper extends BaseMapper<User> {
    
    // 自定义查询方法
    @Select("SELECT * FROM user WHERE username LIKE #{name}")
    List<User> selectByNameLike(@Param("name") String name);
    
    // 复杂查询可以使用 XML
    List<User> selectUserWithOrders(@Param("userId") Long userId);
}

五、Service 层封装

使用 IService 和 ServiceImpl 快速构建业务层:

public interface UserService extends IService<User> {
    User getByUsername(String username);
    
    boolean updateEmail(Long userId, String email);
    
    Page<User> getUserPage(int current, int size, String keyword);
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> 
        implements UserService {
    
    @Override
    public User getByUsername(String username) {
        return lambdaQuery()
                .eq(User::getUsername, username)
                .one();
    }
    
    @Override
    public boolean updateEmail(Long userId, String email) {
        return lambdaUpdate()
                .set(User::getEmail, email)
                .eq(User::getId, userId)
                .update();
    }
    
    @Override
    public Page<User> getUserPage(int current, int size, String keyword) {
        return lambdaQuery()
                .like(StringUtils.isNotBlank(keyword), User::getUsername, keyword)
                .orderByDesc(User::getCreateTime)
                .page(new Page<>(current, size));
    }
}

六、条件构造器

Lambda 条件构造器让代码更加优雅:

// 查询单个
User user = userService.lambdaQuery()
        .eq(User::getUsername, "oinou")
        .eq(User::getDeleted, 0)
        .one();

// 查询列表
List<User> users = userService.lambdaQuery()
        .like(User::getEmail, "@gmail.com")
        .ge(User::getCreateTime, startDate)
        .le(User::getCreateTime, endDate)
        .list();

// 复杂条件
List<User> result = userService.lambdaQuery()
        .and(wrapper -> wrapper
                .like(User::getUsername, keyword)
                .or()
                .like(User::getEmail, keyword))
        .orderByDesc(User::getCreateTime)
        .last("LIMIT 10")
        .list();

七、分页插件

配置分页插件实现物理分页:

@Configuration
public class MybatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

// 使用分页
@GetMapping("/users")
public Page<User> listUsers(
        @RequestParam(defaultValue = "1") int page,
        @RequestParam(defaultValue = "10") int size) {
    return userService.page(new Page<>(page, size));
}

八、自动填充字段

实现 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());
        this.strictInsertFill(metaObject, "deleted", Integer.class, 0);
        this.strictInsertFill(metaObject, "version", Integer.class, 0);
    }
    
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

九、代码生成器

使用代码生成器快速生成 Entity、Mapper、Service、Controller:

public class CodeGenerator {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mydb", "root", "password")
                .globalConfig(builder -> {
                    builder.author("Oinou")
                            .outputDir(System.getProperty("user.dir") + "/src/main/java");
                })
                .packageConfig(builder -> {
                    builder.parent("com.example")
                            .entity("entity")
                            .mapper("mapper")
                            .service("service")
                            .controller("controller");
                })
                .strategyConfig(builder -> {
                    builder.addInclude("user", "order", "product")
                            .entityBuilder()
                            .enableLombok()
                            .enableTableFieldAnnotation()
                            .controllerBuilder()
                            .enableRestStyle();
                })
                .execute();
    }
}

十、性能优化建议

  1. 使用连接池 - 配置 Druid 或 HikariCP 连接池,合理设置最大连接数
  2. 开启二级缓存 - 对于读多写少的场景,开启 MyBatis 二级缓存
  3. 批量操作 - 使用 saveBatch 替代循环插入
  4. SQL 优化 - 使用 @Select 注解编写原生 SQL 处理复杂查询
  5. 索引优化 - 在常用查询字段上建立索引,避免全表扫描

总结

MyBatis-Plus 极大地简化了数据库操作,让我们能够更专注于业务逻辑。通过本文介绍的基础 CRUD、条件构造器、分页插件、自动填充和代码生成等功能,可以快速构建高效的数据访问层。在实际项目中,建议结合具体的业务场景,合理使用 MyBatis-Plus 提供的各种特性。

MyBatis-Plus 不是银弹,对于超复杂的 SQL 查询,仍然建议使用原生 SQL 或 XML 配置,以保证最优的查询性能。