MyBatis-Plus核心功能与实战案例,代码示例基于Spring Boot 3.x + MyBatis-Plus 3.5.3:
一、MyBatis-Plus 基础篇
1. 简介与核心优势
MyBatis-Plus(MP) 是 MyBatis 的增强工具,在保留 MyBatis 原生功能的基础上,通过内置通用 Mapper、Service、条件构造器等,大幅简化开发。
核心优势:
- 无侵入:只做增强不做改变,可与 MyBatis 原生功能混合使用
- 高效开发:内置通用 CRUD 方法,减少 80% 的重复代码
- 强大条件构造器:支持 Lambda 表达式,避免 SQL 注入风险
2. 快速入门
环境搭建
- 创建 Spring Boot 项目
- 使用 start.spring.io 生成项目,选择依赖:
Spring Web
,MySQL Driver
,Lombok
- 使用 start.spring.io 生成项目,选择依赖:
- 引入 MP 依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
- 配置数据源
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启 SQL 日志
第一个 MP 程序
- 定义实体类
@Data
@TableName("user") // 映射表名
public class User {
@TableId(type = IdType.AUTO) // 主键自增
private Long id;
private String name;
private Integer age;
@TableField("email") // 字段映射
private String email;
}
- 创建 Mapper 接口
public interface UserMapper extends BaseMapper<User> {}
- 测试 CRUD
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testInsert() {
User user = new User();
user.setName("Jack");
user.setAge(28);
user.setEmail("jack@example.com");
userMapper.insert(user); // 插入数据
}
@Test
void testSelect() {
User user = userMapper.selectById(1L); // 按 ID 查询
System.out.println(user);
}
}
二、核心功能实战
1. 条件构造器(Wrapper)
查询用户列表(动态条件)
public List<User> queryUsers(String name, Integer minAge) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(name), "name", name)
.ge(minAge != null, "age", minAge)
.orderByDesc("id");
return userMapper.selectList(wrapper);
}
// Lambda 表达式写法(推荐)
public List<User> queryUsersLambda(String name, Integer minAge) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(name), User::getName, name)
.ge(minAge != null, User::getAge, minAge)
.orderByDesc(User::getId);
return userMapper.selectList(wrapper);
}
更新用户邮箱
public void updateEmail(Long userId, String newEmail) {
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id", userId)
.set("email", newEmail);
userMapper.update(null, wrapper); // 参数为 null 表示不更新实体字段
}
2. 分页与排序
- 配置分页插件
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
- 分页查询订单
public Page<Order> pageOrders(int pageNum, int pageSize, String status) {
Page<Order> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Order::getStatus, status);
return orderMapper.selectPage(page, wrapper);
}
3. 自动填充与逻辑删除
自动填充创建时间
- 实体类配置
public class User {
@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());
}
}
逻辑删除配置
- 实体类标记
@TableLogic
private Integer deleted; // 0-未删除,1-已删除
- 全局配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除字段
logic-delete-value: 1 # 删除值
logic-not-delete-value: 0 # 未删除值
三、高级特性与扩展
1. 多数据源配置(以两个数据源为例)
- 引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
- 配置数据源
spring:
datasource:
dynamic:
primary: master
datasource:
master:
url: jdbc:mysql://localhost:3306/db1
username: root
password: 123456
slave:
url: jdbc:mysql://localhost:3306/db2
username: root
password: 123456
- 使用注解切换数据源
@DS("slave") // 指定从库
public List<User> getSlaveUsers() {
return userMapper.selectList(null);
}
2. 自定义 SQL 注入器(扩展全局方法)
- 定义自定义方法
public class DeleteAllMethod extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql = "delete from " + tableInfo.getTableName();
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return addDeleteMappedStatement(mapperClass, "deleteAll", sqlSource);
}
}
- 注册注入器
@Component
public class MySqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methods = super.getMethodList(mapperClass);
methods.add(new DeleteAllMethod());
return methods;
}
}
- Mapper 接口调用
public interface UserMapper extends BaseMapper<User> {
void deleteAll();
}
四、最佳实践与常见问题
1. 最佳实践
- 实体类规范:
- 使用
@TableName
明确表名,避免默认转换(如user_info
→userInfo
) - 避免在实体类中使用数据库关键字(如
order
→ 改用orderNo
)
- 使用
- 事务控制:在 Service 层添加
@Transactional
@Transactional(rollbackFor = Exception.class)
public void updateUserAndLog(User user, String logContent) {
userMapper.updateById(user);
logMapper.insert(new Log(logContent));
}
2. 常见问题排查
- 字段映射失败:
- 检查
@TableField
注解的value
是否与数据库字段名一致 - 查看 SQL 日志确认生成的 SQL 语句
- 检查
- 分页失效:
- 确保配置了
PaginationInnerInterceptor
- 检查 Page 对象是否作为第一个参数传入
- 确保配置了
五、综合实战项目:博客系统
1. 数据库设计
CREATE TABLE `article` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(100) NOT NULL,
`content` TEXT,
`author_id` BIGINT NOT NULL,
`create_time` DATETIME
);
CREATE TABLE `comment` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`article_id` BIGINT NOT NULL,
`content` VARCHAR(500),
`user_id` BIGINT NOT NULL
);
2. 代码生成器配置
FastAutoGenerator.create("jdbc:mysql://localhost:3306/blog", "root", "123456")
.globalConfig(builder -> builder.author("YourName").outputDir("src/main/java"))
.packageConfig(builder -> builder.parent("com.example.blog"))
.strategyConfig(builder -> builder.addInclude("article", "comment"))
.execute();
3. 核心功能实现
文章分页查询:
public Page<Article> pageArticles(int pageNum, int pageSize, String keyword) {
Page<Article> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Article> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(keyword), Article::getTitle, keyword);
return articleMapper.selectPage(page, wrapper);
}
评论事务处理:
@Transactional
public void addComment(Comment comment) {
commentMapper.insert(comment);
// 更新文章评论数
articleMapper.update(null,
new UpdateWrapper<Article>()
.eq("id", comment.getArticleId())
.setSql("comment_count = comment_count + 1"));
}
通过以上内容,开发者可系统掌握 MyBatis-Plus 的核心功能,并具备企业级项目开发能力。建议结合官方文档与实战项目深化理解。