算账机器人 使用saveBatch()方法批量插入数据时
一、批量插入效率低下
问题场景:使用saveBatch()方法批量插入数据时,测试环境表现正常,但生产环境出现接口响应缓慢,
耗时可达数秒。查看SQL日志发现,框架实际执行的是单条插入语句循环,而非真正的批量插入。 原因
分析:MyBatis-Plus的saveBatch()默认并未开启JDBC批量提交优化,即使调用批量方法,底层仍逐条
执行INSERT语句。 解决方案:在数据库连接URL中添加rewriteBatchedStatements=true参数(仅针对
MySQL驱动有效),同时确保MyBatis-Plus版本在3.4.0以上,该版本优化了批量插入的执行逻辑。
二、自动填充字段不生效
问题场景:配置了MetaObjectHandler实现类处理创建时间、更新时间等字段的自动填充,但插入或更新
数据时,目标字段始终为null。 原因分析:
实体类字段未添加
@TableField(fill = FieldFill.INSERT)或@TableField(fill = FieldFill.INSERT_UPDATE)注解,默认填充策略为FieldFill.DEFAULT,不会触发自动填充;实体类字段名与数据库字段名映射错误,导致填充逻辑无法匹配到目标字段;
MetaObjectHandler实现类未被Spring容器扫描到,未添加@Component注解。 解决方案:在需要自动填充的字段上明确指定填充策略;
确保
@TableField注解的字段映射关系正确;检查
MetaObjectHandler实现类的组件扫描配置。
三、分页查询失效
问题场景:调用page()方法进行分页查询时,返回结果包含全量数据,分页参数未生效。 原因分析:
未配置MyBatis-Plus的分页插件
MybatisPlusInterceptor,框架无法拦截分页查询语句进行分页处理;分页参数设置错误,如当前页设置为0或负数,或每页数量设置为0;
自定义SQL语句时未正确使用分页参数,如在XML映射文件中未添加
LIMIT关键字。 解决方案:在Spring配置类中注册分页插件:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
确保分页参数设置合理,当前页从1开始,每页数量大于0;
自定义SQL时,使用MyBatis-Plus提供的分页参数
page和size。
四、逻辑删除与查询冲突
问题场景:配置逻辑删除后,调用selectById()等查询方法时,无法查询到已被逻辑删除的数据,即使在QueryWrapper中手动添加逻辑删除字段的条件也不生效。 原因分析:MyBatis-Plus的逻辑删除插件会自动在查询语句中添加WHERE 逻辑删除字段 = 未删除值的条件,手动添加的条件会被覆盖。 解决方案:
若需查询已删除数据,使用
selectObjs()等方法配合自定义SQL;在
application.yml中配置逻辑删除的全局字段和值:
mybatis-plus:
global-config:
db-config:
logic-delete-field: isDeleted
logic-delete-value: 1
logic-not-delete-value: 0
五、乐观锁更新失败
问题场景:配置乐观锁插件后,更新数据时未触发版本号递增,并发场景下仍出现数据覆盖问题。 原因分析:
实体类未添加
@Version注解标记版本号字段;未注册乐观锁插件
OptimisticLockerInnerInterceptor;更新数据时未携带版本号,或版本号与数据库中不一致。 解决方案:
在实体类版本号字段上添加
@Version注解;在分页插件中注册乐观锁拦截器;
更新数据时,确保从数据库查询出最新版本号并传入更新方法。
六、字段自动映射失效
问题场景:实体类中的部分字段无法与数据库字段自动映射,查询结果中对应字段为null。 原因分析:
实体类字段名采用驼峰命名,而数据库字段名采用下划线命名,但未开启驼峰命名自动映射;
字段名存在关键字冲突,如
order、user等,未添加反引号转义;实体类字段添加了
@TableField(exist = false)注解,标记为非数据库字段。 解决方案:在
application.yml中开启驼峰命名映射:
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
对关键字字段添加
@TableField("order")注解进行转义;检查
@TableField注解的exist属性设置是否正确。
七、代码生成器生成的XML文件重复
问题场景:使用MyBatis-Plus代码生成器时,多次执行生成操作会导致XML映射文件中重复生成SQL语句。 原因分析:代码生成器默认采用追加模式生成XML文件,而非覆盖模式。 解决方案:
在代码生成器配置中设置
fileOverride = true,开启文件覆盖模式;生成前手动清理目标目录下的旧文件;
配置自定义的模板引擎,修改XML文件生成逻辑。
八、多租户插件数据隔离失效
问题场景:配置多租户插件后,部分查询语句未自动添加租户ID条件,导致数据隔离失效。 原因分析:
未在实体类上添加
@TableName(autoResultMap = true)注解,多租户插件无法识别需要添加租户条件的表;自定义SQL语句时未使用MyBatis-Plus的Wrapper查询,插件无法拦截添加租户条件;
多租户插件配置错误,如租户ID字段名设置错误。 解决方案:
在实体类上添加
@TableName(autoResultMap = true)注解;尽量使用MyBatis-Plus提供的Wrapper查询,避免直接编写XML映射文件;
检查多租户插件的租户ID字段名配置是否与数据库字段一致。
九、枚举类型映射错误
问题场景:实体类中使用枚举类型字段,插入或查询数据时出现类型转换异常,或数据库中存储的枚举值与预期不符。 原因分析:
未配置枚举类型的处理器,MyBatis无法将枚举类型与数据库字段进行转换;
枚举类未实现
IEnum接口,或未指定枚举值的存储类型。 解决方案:在
application.yml中配置枚举类型处理器:
mybatis-plus:
configuration:
type-handlers-package: com.example.handler
自定义枚举类型处理器,或让枚举类实现
IEnum接口:
public enum StatusEnum implements IEnum<Integer> {
NORMAL(0, "正常"),
DISABLED(1, "禁用");
private final int value;
private final String desc;
StatusEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
@Override
public Integer getValue() {
return value;
}
}
十、关联查询性能低下
问题场景:使用MyBatis-Plus的关联查询功能时,出现N+1查询问题,导致接口响应缓慢。 原因分析:MyBatis-Plus的关联查询默认采用懒加载模式,当访问关联对象时会触发额外的查询语句,若查询数据量较大,会产生大量SQL语句,影响性能。 解决方案:
配置关联查询的贪婪加载模式,在查询主表时一次性加载关联数据;
使用自定义SQL语句,通过JOIN查询一次性获取主表和关联表数据;
合理设置关联查询的触发条件,避免不必要的关联数据加载。