确认
- [X] 我的版本是最新版本, 我的版本号与 version 相同, 并且项目里无依赖冲突
- [X] 我已经在 issue 中搜索过, 确认问题没有被提出过
- [X] 我已经修改标题, 将标题中的 描述 替换为遇到的问题
功能改进
希望达到 insert into t_user values(), (), (); 这种效果; 使用官方提供的方法注入插件 insertIntoSomeColumn 会出现源码中注释提到的数据库默认值的问题,所以基于此我这边 利用注入插件以及拦截器两个地方来实现真正的批量插入。原理就是通过具体的values反推出所需要的列。自定义的MysqlInsertBatch 里面只做 insertBatch 方法的MappedStatement对象添加 ,真正的批量sql生成由后边自定义的MysqlInsertBatchInterceptor来完成,部分源码片断
此种批量添加要求:必须保证每个value里面的参数个数与类型完全一样
不知是否可采纳
参考资料
No response
Comment From: chess3cake
我是通过重载mapper/service方法解决的。Myabtisplus的BatchMethod用的是BatchStatement,但是切换BatchStatement/SimpleStatement存在可见性的问题,所以我都统一改成用SimpleStatement了。
Comment From: fengyujun
我这个是通过SqlInjector来实现的,定义一个新的批量插入方法,然后通过上面的流程来实现这个方法的内部逻辑。你这个具体是怎么实现的呢
Comment From: chess3cake
我这个是通过SqlInjector来实现的,定义一个新的批量插入方法,然后通过上面的流程来实现这个方法的内部逻辑。你这个具体是怎么实现的呢
我也是通过SqlInjector实现的,我是直接用Method生成了一个动态sql。重载DefaultSqlInjector,可以注册自定义的mapper method。
Comment From: fengyujun
我这个是通过SqlInjector来实现的,定义一个新的批量插入方法,然后通过上面的流程来实现这个方法的内部逻辑。你这个具体是怎么实现的呢
我也是通过SqlInjector实现的,我是直接用Method生成了一个动态sql。重载DefaultSqlInjector,可以注册自定义的mapper method。
但是你这个时候能确定具体有哪些列吗
Comment From: chess3cake
我这个是通过SqlInjector来实现的,定义一个新的批量插入方法,然后通过上面的流程来实现这个方法的内部逻辑。你这个具体是怎么实现的呢
我也是通过SqlInjector实现的,我是直接用Method生成了一个动态sql。重载DefaultSqlInjector,可以注册自定义的mapper method。
但是你这个时候能确定具体有哪些列吗
你的意思是,同一张表的批量插入,每次用的列不一样吗?
Comment From: fengyujun
我这个是通过SqlInjector来实现的,定义一个新的批量插入方法,然后通过上面的流程来实现这个方法的内部逻辑。你这个具体是怎么实现的呢
我也是通过SqlInjector实现的,我是直接用Method生成了一个动态sql。重载DefaultSqlInjector,可以注册自定义的mapper method。
但是你这个时候能确定具体有哪些列吗
你的意思是,同一张表的批量插入,每次用的列不一样吗?
对,根据用户给哪些属性赋值了,则将哪些属性转换为对应的sql列,而不能直接将对应的实体所有属性转换为列
Comment From: chess3cake
我这个是通过SqlInjector来实现的,定义一个新的批量插入方法,然后通过上面的流程来实现这个方法的内部逻辑。你这个具体是怎么实现的呢
我也是通过SqlInjector实现的,我是直接用Method生成了一个动态sql。重载DefaultSqlInjector,可以注册自定义的mapper method。
但是你这个时候能确定具体有哪些列吗
你的意思是,同一张表的批量插入,每次用的列不一样吗?
对,根据用户给哪些属性赋值了,则将哪些属性转换为对应的sql列,而不能直接将对应的实体所有属性转换为列
在我的mapper里有这么个基础方法,SqlMethod.DYNAMIC_INSERT_BATCH通过injector生成,在该方法中对不同null值的插入进行分组,再批量插入
`
default int insertBatch(@Param(Constants.COLL) Collection
MutableListMultimap<MultiObject, T> bulkEntities = Multimaps.mutable.list.empty();
for (T entity : entities) {
if (entity == null) {
continue;
}
MultiObject nullOrEmptyFields = new MultiObject();
try {
if (fieldsList == null) {
fieldsList = FieldUtils.getAllFieldsList(entity.getClass());
}
for (Field field : fieldsList) {
String fieldName = field.getName();
Object fieldValue = FieldUtils.readField(field, entity);
if (fieldValue == null) {
nullOrEmptyFields.addObj(fieldName);
} else if (fieldValue instanceof String str && str.isEmpty()) {
nullOrEmptyFields.addObj(fieldName);
} else if (fieldValue instanceof Collection<?> coll && coll.isEmpty()) {
nullOrEmptyFields.addObj(fieldName);
} else if (fieldValue instanceof Map<?, ?> map && map.isEmpty()) {
nullOrEmptyFields.addObj(fieldName);
}
}
} catch (Exception e) {
throw new EyTaxException("-1", "Failed to get field", e);
}
bulkEntities.put(nullOrEmptyFields, entity);
}
MybatisMapperProxy<?> mybatisMapperProxy = MybatisUtils.getMybatisMapperProxy(this);
Class<?> mapperInterface = mybatisMapperProxy.getMapperInterface();
SqlSession sqlSession = mybatisMapperProxy.getSqlSession();
int res = 0;
for (MultiObject bulk : bulkEntities.keySet()) {
for (List<T> partition : ListUtils.partition(bulkEntities.get(bulk), batchSize)) {
Map<String, Object> params = new HashMap<>();
params.put(Constants.COLL, partition);
params.put(Constants.MP_FILL_ET, partition.get(0));
res += sqlSession.insert(mapperInterface.getName() + StringPool.DOT + SqlMethod.DYNAMIC_INSERT_BATCH.getMethod(), params);
}
}
return res;
}
`