代码生成与性能优化
MyBatis-Plus 提供代码生成器快速生成 Entity、Mapper、Service、Controller 等代码,减少重复劳动。本章还介绍批量操作优化、SQL 性能分析和常见问题排查。
代码生成器
添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.12</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>FastAutoGenerator 配置(推荐)
MyBatis-Plus 3.5.1+ 提供了 FastAutoGenerator,比旧版 AutoGenerator 更简洁:
package com.xiaoye.mybatisplus.generator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root1234";
String moduleName = "system";
String mapperLocation = "/src/main/resources/mapper/" + moduleName;
FastAutoGenerator.create(url, username, password)
.globalConfig(builder -> {
builder.author("xiaoye")
.outputDir(System.getProperty("user.dir") + "/src/main/java")
.enableSwagger(); // 生成 Swagger 注解
})
.packageConfig(builder -> {
builder.parent("com.xiaoye.mybatisplus")
.moduleName(moduleName)
.pathInfo(Collections.singletonMap(
OutputFile.xml,
System.getProperty("user.dir") + mapperLocation
));
})
.strategyConfig(builder -> {
builder.addInclude("user") // 指定要生成的表
.addTablePrefix("t_", "sys_") // 过滤表前缀
.entityBuilder()
.enableLombok() // 使用 Lombok
.enableTableFieldAnnotation() // 生成 @TableField 注解
.controllerBuilder()
.enableRestStyle() // 生成 @RestController
.mapperBuilder()
.enableMapperAnnotation(); // 生成 @Mapper 注解
})
.templateEngine(new VelocityTemplateEngine())
.execute();
}
}生成的文件结构
src/main/java/com/xiaoye/mp/system/
├── entity/
│ └── User.java
├── mapper/
│ └── UserMapper.java
├── service/
│ ├── UserService.java
│ └── impl/
│ └── UserServiceImpl.java
└── controller/
└── UserController.java
src/main/resources/mapper/system/
└── UserMapper.xml- 开发初期使用:快速搭建项目骨架,生成基础 CRUD 代码
- 不要反复重新生成:生成后的代码应该由开发者维护,反复重新生成会覆盖自定义逻辑
- 生产环境删除生成器依赖:代码生成器是开发工具,不应出现在生产环境的依赖中
- 配合自定义模板:团队可以根据项目规范自定义生成模板
批量操作优化
Service 层批量方法
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService {
// 批量插入
@Transactional(rollbackFor = Exception.class)
public void batchInsertUsers(List<User> users) {
// saveBatch 默认每批 1000 条,可以自定义批次大小
saveBatch(users, 500); // 每批 500 条
}
// 批量更新
@Transactional(rollbackFor = Exception.class)
public void batchUpdateUsers(List<User> users) {
updateBatchById(users, 500);
}
// 批量插入或更新(根据 ID 是否存在自动判断)
@Transactional(rollbackFor = Exception.class)
public void batchSaveOrUpdate(List<User> users) {
saveOrUpdateBatch(users, 500);
}
}批量操作的性能考量
// × 性能差:逐条插入(1000 条 = 1000 次 SQL 执行)
for (User user : userList) {
userMapper.insert(user);
}
// √ 性能好:批量插入(1000 条 = 2 批次 × 500 条/批)
saveBatch(userList, 500);- 批次大小不宜过大:推荐 500-1000 条/批,过大可能导致 SQL 超长或内存溢出
- 必须搭配事务:批量操作应该在事务中执行,否则部分失败会导致数据不一致
- 批量更新只更新非 null 字段:
updateBatchById默认只更新实体中非 null 的字段 - MySQL 批量插入优化:确保 MySQL 连接参数包含
rewriteBatchedStatements=true,可以将多条 INSERT 合并为一条
MySQL 批量插入配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?rewriteBatchedStatements=true这个参数让 MySQL JDBC 驱动将 INSERT INTO ... VALUES (...); INSERT INTO ... VALUES (...); 合并为 INSERT INTO ... VALUES (...), (...), (...);,大幅提升批量插入性能。
SQL 性能分析
开发环境 SQL 日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL 和参数StdOutImpl 会将每条 SQL 打印到控制台,生产环境必须关闭,否则会产生大量日志影响性能。生产环境使用 Slf4jImpl 或 NologgingImpl。
P6Spy 性能分析
P6Spy 可以拦截 SQL 并记录执行时间,方便定位慢查询:
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>3.9.1</version>
</dependency>spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaispy.properties 配置:
modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
databaseDialectDateFormat=yyyy-MM-dd HH:mm:ss
outagedetection=true
outagedetectioninterval=1 # 执行时间超过1秒的SQL会被标记P6Spy 会增加 SQL 执行开销,生产环境不应使用。定位慢查询应该使用 MySQL 的慢查询日志和 EXPLAIN。
常见问题与排障
问题一:字段映射失败
现象:数据库字段 user_name 无法映射到实体类属性 userName
原因:未开启驼峰命名转换
解决:
mybatis-plus:
configuration:
map-underscore-to-camel-case: true问题二:主键生成异常
现象:使用 ASSIGN_ID 策略时,ID 过长(19位数字)
原因:实体类主键类型使用了 Integer 而非 Long
解决:雪花算法生成的 ID 是 Long 型(最大 19 位),实体类必须使用 Long 或 String
// × 错误:Integer 无法承载雪花算法生成的 ID
@TableId(type = IdType.ASSIGN_ID)
private Integer id;
// √ 正确:使用 Long
@TableId(type = IdType.ASSIGN_ID)
private Long id;问题三:分页不生效
现象:selectPage 返回全部数据而非分页结果
原因:未配置分页插件
解决:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}问题四:逻辑删除不生效
现象:逻辑删除后仍能查询到数据
原因:缺少 @TableLogic 注解或全局配置
解决:
// 方式一:注解配置(推荐)
@TableLogic
private Integer deleted;
// 方式二:全局配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0问题五:批量操作报错 StackOverflow
现象:批量插入/更新大量数据时出现 StackOverflowError
原因:一次性操作数据量过大
解决:
- 降低批次大小(500 条/批)
- 分批处理,每批单独提交
- 确保 MySQL 连接参数包含
rewriteBatchedStatements=true
最佳实践总结
| 领域 | 核心原则 |
|---|---|
| 代码生成 | 初期使用、后期维护、不反复重新生成 |
| 批量操作 | 控制批次大小、搭配事务、开启 rewriteBatchedStatements |
| SQL 分析 | 开发环境用日志/P6Spy、生产环境用慢查询日志 + EXPLAIN |
| 问题排查 | 检查插件配置、注解配置、数据类型匹配 |
下一步:回到 MyBatis-Plus 总览 回顾完整知识体系,或结合 Spring Boot 总览 将 MyBatis-Plus 集成到实际项目中。
版本差异(旧版 3.5.5 → 3.5.x)
| 特性 | 旧版(3.5.5 时期) | 当前 3.5.x(如 3.5.12) |
|---|---|---|
| 代码生成器 | AutoGenerator(旧)/ FastAutoGenerator(3.5.1+) | FastAutoGenerator 为主推,旧版 AutoGenerator 不再更新 |
| 批量操作 | saveBatch/updateBatchById | 用法不变;搭配 rewriteBatchedStatements 优化原则不变 |
| SQL 分析 | 日志/P6Spy/慢查询 | 不变;3.5.x 内置 SQL 解析继续基于 JSqlParser |
| 虚拟线程 | 无特殊处理 | 3.5.9+ 优化虚拟线程环境兼容 |
代码生成器部分:从 3.5.5 升级到 3.5.12 时,若仍使用旧版 AutoGenerator,建议迁移到 FastAutoGenerator(API 更简洁且持续维护)。