文章目录
- 一、主题
- 二、效果展示
- 三、mybatis-plus源码分析
- 四、优化思路
- 五、代码优化
- 方法一:修改批量新增SQL
- 方法二:使用insertBatchSomeColumn 方法
一、主题
经发现,mybatisPlus只有Service中存在saveBatch()方法,而Mapper中不存在批量新增的方法,深入了解,发现mybatisPlus的Service中saveBatch()方法也是循环一条一条插入数据库。如果发现数据量较大,运行时间较长。所以文本针对mapper无批量新增和效率实现新增优化。
二、效果展示
这里使用600条数据在模拟mybatisPlus新增和优化之后的新增。看一下有什么区别
输出的结果:
可以看到600条数据,mybatisPlus自带的批量新增使用时间8s,而通过修改SQL的方法只用了1秒。
三、mybatis-plus源码分析
通过效果图中可以看到批量新增本质上还是insert触发单个新增,这样无异于循环新增。
四、优化思路
上述mybatis-plus中源码中只是循环插入实现的批量新增,优化方式有以下几个思路。可能还有别的优化思路,欢迎评论区讨论发言。本文只实现思路1和3
- 把批量数据拼接成一个insert的SQL语句。
- 多线程任务去批量新增。
- 根据mybatis-plus预留的 insertBatchSomeColumn 方法。可能
五、代码优化
方法一:修改批量新增SQL
-
此方法手动给mapper新增一个批量新增方法,如效果展示的代码中goodsLabelValueService.saveBatchList(labelGoodsValueList2);
-
Service中
int saveBatchList(List<LabelGoodsValue> labelGoodsValueList);
-
serviceImpl中
@Override public int saveBatchList(List<LabelGoodsValue> labelGoodsValueList) { return baseMapper.saveBatchList(labelGoodsValueList); }
-
Mapper.java中
int saveBatchList(@Param("list") List<LabelGoodsValue> labelGoodsValueList);
-
Mapper.xml中
<insert id="saveBatchList"> insert into label_goods_value ( id,label_id , label_name , goods_spu_id , goods_spu_name , sort , create_time , update_time , spu_code ) values <foreach item="item" index="index" collection="list" separator=","> (#{item.id},#{item.labelId}, #{item.labelName}, #{item.goodsSpuId}, #{item.goodsSpuName}, #{item.sort}, #{item.createTime}, #{item.updateTime}, #{item.spuCode}) </foreach> </insert>
-
看到这里,这里提取Mapper.xml的方法,使代码生成的VM的自动生成(VM是mybatisPlus代码生成的模板)
<insert id="saveBatchList"> insert into $tableName (#foreach($column in $columns) ${column.columnName} #if($foreach.count != $columns.size()),#end#end) values <foreach item="item" index="index" collection="list" separator=","> (#foreach($column in $columns) #{item.${column.lowerAttrName}}#if($foreach.count != $columns.size()),#end#end) </foreach> </insert>
方法二:使用insertBatchSomeColumn 方法
-
新建 Sql 注射器 BatchSqlInjector
import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn; import java.util.List; public class BatchSqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) { List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo); methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE)); return methodList; } }
-
MybatisPlusConfig 配置 BatchSqlInjector Bean
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableTransactionManagement @Configuration public class MybatisPlusConfig { /** * 批量插入 * * @return */ @Bean public BatchSqlInjector easySqlInjector() { return new BatchSqlInjector(); } }
-
配置 BatchBaseMapper 继承 BaseMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.Collection; public interface BatchBaseMapper<T> extends BaseMapper<T> { /** * 批量插入 仅适用于mysql * * @param entityList 实体列表 * @return 影响行数 */ Integer insertBatchSomeColumn(Collection<T> entityList); }
-
业务 Mapper 继承 BatchBaseMapper
@Repository public interface ISapCustomerMapper extends BatchBaseMapper<SapCustomerPO> { }
-
service 创建 createBatch 作为新的批量插入方法
public class SapCustomerServiceImpl extends ServiceImpl<ISapCustomerMapper, SapCustomerPO> { void createBatch(List<SapCustomerPO> entityList) { if(!entityList.isEmpty()){ baseMapper.insertBatchSomeColumn(entityList); } } }
-
注意事项:
- 在使用 MyBatis-Plus 进行批量新增指定字段时,需要注意以下几点:
- 每次新增的数据量不要过大,建议每批次新增的数据量控制在 1000 条以内。
- 要新增的指定字段不能为 null,需要手动设置默认值。
- 如果要新增的指定字段在实体类中有对应的字段值,会被忽略。