在日常的 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();
}
}
十、性能优化建议
- 使用连接池 - 配置 Druid 或 HikariCP 连接池,合理设置最大连接数
- 开启二级缓存 - 对于读多写少的场景,开启 MyBatis 二级缓存
- 批量操作 - 使用 saveBatch 替代循环插入
- SQL 优化 - 使用 @Select 注解编写原生 SQL 处理复杂查询
- 索引优化 - 在常用查询字段上建立索引,避免全表扫描
总结
MyBatis-Plus 极大地简化了数据库操作,让我们能够更专注于业务逻辑。通过本文介绍的基础 CRUD、条件构造器、分页插件、自动填充和代码生成等功能,可以快速构建高效的数据访问层。在实际项目中,建议结合具体的业务场景,合理使用 MyBatis-Plus 提供的各种特性。
MyBatis-Plus 不是银弹,对于超复杂的 SQL 查询,仍然建议使用原生 SQL 或 XML 配置,以保证最优的查询性能。