前言
首先我们常用的方法一般是saveOrUpdateBatch(),源码长这样:
下面看看executeBatch怎么在处理数据
可以简单看出来他确实是一个for循环,只不过到指定次数进行一次flush,减少了sqlsession.flushStatements()的耗时。sql日志打印,也确实是一条条出现的。
那么有没有一种真正的批量操作呢?
发现
经过网上一番查找,发现mp本身提供批量功能,但是为了兼容多种数据库的考量,选择在扩展功能引入真正的批量方法。
新实践
导入扩展包
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.5.2</version>
</dependency>
定义一个自己的拦截器
public class MyInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
//增加自己想要的方法, 必须是AbstractMethod的子类
methodList.add(new InsertBatchSomeColumn());//InsertBatchSomeColumn就是扩展包里
return methodList;
}
}
注入拦截器
@Configuration
@Slf4j
@MapperScan("com.rikka.sqlgenerator.mapper") //注意这里扫描路径
public class MybatisPlusConfig {
/**
* 注入拦截器
* @return
*/
@Bean
public MyInjector myInjector() {
return new MyInjector();
}
}
新增一个自己的mapper
@Configuration
@Slf4j
@MapperScan("com.rikka.sqlgenerator.mapper")
public class MybatisPlusConfig {
/**
* 注入拦截器
* @return
*/
@Bean
public MyInjector myInjector() {
return new MyInjector();
}
}
让原mapper改为继承RootMapper
public interface SysSequenceMapper extends RootMapper<SysSequence> {
}
编写测试类
@SpringBootTest
public class BatchMethodTest {
@Resource
private SysSequenceMapper sysSequenceMapper;
/**
* 测试批量方法
*/
@Test
@Transactional(rollbackFor = Exception.class) //测试类会让数据库回滚
// @Rollback(value = false)
public void testBatchMethod() {
ArrayList<SysSequence> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
SysSequence sysSequence = new SysSequence();
sysSequence.setSeqName("t_test" + i);
sysSequence.setCurrentVal(1);
sysSequence.setInitVal(1);
sysSequence.setIncrementVal(1);
sysSequence.setMaxVal(99999999);
sysSequence.setMinVal(1);
sysSequence.setCreateTime(LocalDateTime.now());
sysSequence.setUpdateTime(LocalDateTime.now());
list.add(sysSequence);
}
sysSequenceMapper.insertBatchSomeColumn(list);
}
}
可以看到确实是批量进行插入
后记-查询批量新增的额外收获
mp除了提供通过id批量修改,也没有提供根据字段来修改,那么我们可以不可以改造它原有的方法呢?答案是可以的。根据上面的saveOrUpdate源码进行修改。例子如下。
但是我不是很满意,觉得入参传一个固定值,这样很傻。所以我找到了一个新办法
接口定义一个新方法
public interface ISysSequenceService extends IService<SysSequence> {
/**
* 批量根据指定的updateWrapper进行修改
* @param entityList
* @param batchSize
* @param updateWrapperFunction
* @param <T>
* @return
*/
<T> boolean batchUpdate(Collection<T> entityList, int batchSize, Function<T, LambdaUpdateWrapper> updateWrapperFunction);//这里传的是Function<T, R>, 返回值是一个updateWrapper
}
实现类
@Service
public class SysSequenceServiceImpl extends ServiceImpl<SysSequenceMapper, SysSequence> implements ISysSequenceService {
@Override
public <T> boolean batchUpdate (Collection<T>entityList, int batchSize, Function<T, LambdaUpdateWrapper> updateWrapperFunction) {
String sqlStatement = getSqlStatement(SqlMethod.UPDATE);//这里修改为UPDATE
return executeBatch(entityList, batchSize, (sqlSession, entity) -> {
HashMap<Object, Object> param = CollectionUtils.newHashMapWithExpectedSize(2);
param.put(Constants.ENTITY, entity);
param.put(Constants.WRAPPER, updateWrapperFunction.apply(entity));//这里巧妙的用到了entity,做到了灵活赋值,又根据的是你传入的Function来进行操作,非常nice
sqlSession.update(sqlStatement, param);
});
}
}
实际调用(两种写法看你喜欢)
sysSequenceService.batchUpdate(updateList, 100, sysSequence -> Wrappers.<SysSequence>lambdaUpdate().eq(SysSequence::getSeqName, sysSequence.getSeqName()));
sysSequenceService.batchUpdate(updateList, 100, sysSequence -> new LambdaUpdateWrapper<SysSequence>().eq(SysSequence::getSeqName, sysSequence.getSeqName()));
参考
1.自定义sql批量实现原理是继承AbstractMethod重写injectMappedStatement方法
https://blog.csdn.net/sadnskajf/article/details/126748605?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EAD_ESQUERY%7Eyljh-3-126748605-blog-109102424.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EAD_ESQUERY%7Eyljh-3-126748605-blog-109102424.pc_relevant_aa&utm_relevant_index=5
2.实现真正的批量方法
https://blog.csdn.net/qq_50652600/article/details/126038809?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-126038809-blog-126134485.pc_relevant_3mothn_strategy_and_data_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-126038809-blog-126134485.pc_relevant_3mothn_strategy_and_data_recovery&utm_relevant_index=5
3.优化方法入参
https://www.panziye.com/java/4641.html