MyBatisPlus高效开发实践指南
引言
在现代企业级应用开发中,数据持久层框架的选择对开发效率和系统性能有着至关重要的影响。MyBatis作为一款优秀的持久层框架,在国内拥有广泛的应用基础。而MyBatisPlus在MyBatis的基础上进行了深度封装和功能增强,为开发者提供了更加便捷、高效的开发体验。本文将深入探讨MyBatisPlus的核心特性、使用方法和最佳实践,帮助开发者充分利用这一强大工具提升开发效率。
MyBatisPlus概述
什么是MyBatisPlus
MyBatisPlus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。它内置了通用的Mapper和Service,通过少量的配置即可实现单表的大部分CRUD操作,同时提供了强大的条件构造器,满足各类复杂查询需求。
核心特性
- 无侵入性:只在MyBatis的基础上进行扩展,不会影响现有项目
- 强大的CRUD操作:内置通用Mapper,实现单表CRUD操作无需编写XML
- 支持Lambda形式调用:通过Lambda表达式,避免字段硬编码
- 支持主键自动生成:内置多种主键策略,支持分布式唯一ID生成
- 内置分页插件:基于MyBatis物理分页,无需关心具体实现
- SQL性能分析插件:开发环境支持SQL执行效率分析,快速定位慢查询
- 全局拦截插件:提供全表删除、更新操作阻断机制
环境配置与集成
依赖引入
在Spring Boot项目中引入MyBatisPlus Starter依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
基础配置
在application.yml中进行基础配置:
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
启动类配置
在Spring Boot启动类上添加Mapper扫描注解:
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
实体类设计与注解
基础实体类设计
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String email;
private Integer age;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic
private Integer deleted;
}
常用注解详解
- @TableName:指定数据库表名
- @TableId:指定主键字段,支持多种主键策略
- @TableField:指定字段映射关系,支持自动填充
- @TableLogic:逻辑删除注解
- @Version:乐观锁注解
字段自动填充策略
实现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());
}
}
Mapper层开发实践
基础Mapper接口
public interface UserMapper extends BaseMapper<User> {
// 自定义方法
List<User> selectByAgeGreaterThan(@Param("age") Integer age);
}
自定义SQL实现
在对应的XML文件中实现自定义SQL:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectByAgeGreaterThan" resultType="com.example.entity.User">
SELECT * FROM user WHERE age > #{age} AND deleted = 0
</select>
</mapper>
通用Mapper方法详解
BaseMapper提供了丰富的通用方法:
- insert:插入记录
- deleteById:根据主键删除
- updateById:根据主键更新
- selectById:根据主键查询
- selectBatchIds:根据主键批量查询
- selectByMap:根据条件查询
- selectPage:分页查询
Service层封装技巧
基础Service接口
public interface UserService extends IService<User> {
// 自定义业务方法
List<User> findActiveUsers();
Page<User> findUsersByPage(Page<User> page, UserQuery query);
}
Service实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
public List<User> findActiveUsers() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getDeleted, 0)
.orderByDesc(User::getCreateTime);
return this.list(wrapper);
}
@Override
public Page<User> findUsersByPage(Page<User> page, UserQuery query) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(query.getUsername()),
User::getUsername, query.getUsername())
.ge(query.getMinAge() != null,
User::getAge, query.getMinAge())
.le(query.getMaxAge() != null,
User::getAge, query.getMaxAge())
.eq(User::getDeleted, 0);
return this.page(page, wrapper);
}
}
事务管理
@Service
@Transactional(rollbackFor = Exception.class)
public class UserTransactionService {
@Autowired
private UserService userService;
public void batchUpdateUsers(List<User> users) {
for (User user : users) {
userService.updateById(user);
}
}
}
条件构造器深度解析
QueryWrapper使用
// 创建查询条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("id", "username", "email")
.like("username", "张")
.between("age", 18, 30)
.isNotNull("email")
.orderByDesc("create_time");
List<User> users = userMapper.selectList(wrapper);
LambdaQueryWrapper优势
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.select(User::getId, User::getUsername, User::getEmail)
.like(User::getUsername, "张")
.between(User::getAge, 18, 30)
.isNotNull(User::getEmail)
.orderByDesc(User::getCreateTime);
List<User> users = userMapper.selectList(lambdaWrapper);
复杂条件组合
public List<User> complexQuery(UserQuery query) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// 条件组合
wrapper.and(qw -> qw
.like(User::getUsername, query.getKeyword())
.or()
.like(User::getEmail, query.getKeyword()))
.ge(User::getAge, query.getMinAge())
.le(User::getAge, query.getMaxAge())
.in(User::getStatus, query.getStatusList())
.groupBy(User::getType)
.having("COUNT(*) > {0}", 1);
return userMapper.selectList(wrapper);
}
分页查询最佳实践
分页配置
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
分页查询实现
public Page<User> searchUsers(UserSearchDTO searchDTO) {
// 创建分页对象
Page<User> page = new Page<>(searchDTO.getCurrent(), searchDTO.getSize());
// 构建查询条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(searchDTO.getKeyword()),
User::get

评论框