背景

有时候使用insert into xxx values (),()语句插入大量数据时,会使得SQL语句超长,为了解决这个问题,在Mybatis中编写一个分批次插入的插件。

实现

package com.wangtao.plugin.interceptor;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; /**
* 针对SQL insert into values(), ()语句, 为了避免大量数据使得SQL语句超长, 分批次插入
* 使用方式: 插入集合的name为_batchList, 最大的数目name为_maxCount
* <pre> {@code
* int batchInsert(@Param("_batchList")List<User> users, @Param("_maxCount")int maxCount);
* }</pre>
* Created at 2022/8/24 21:24
*/
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class BatchInsertInterceptor implements Interceptor { /**
* 参数名字
*/
public static final String DEFAULT_DATA_NAME = "_batchList"; /**
* 一次插入的最大条数参数名
*/
public static final String DEFAULT_MAX_COUNT_NAME = "_maxCount"; private static final int DEFAULT_MAX_COUNT = 100; private final Logger logger = LoggerFactory.getLogger(BatchInsertInterceptor.class); private String dataName = DEFAULT_DATA_NAME; private String maxCountName = DEFAULT_MAX_COUNT_NAME; @Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
Executor executor = (Executor) invocation.getTarget();
Configuration configuration = ms.getConfiguration();
MetaObject metaObject = configuration.newMetaObject(parameter);
if (metaObject.hasGetter(dataName)) {
Object dataList = metaObject.getValue(dataName);
int maxCount = DEFAULT_MAX_COUNT;
if (metaObject.hasGetter(maxCountName)) {
maxCount = (Integer) metaObject.getValue(maxCountName);
}
if (dataList instanceof List) {
List<?> list = (List<?>) dataList;
if (list.size() > maxCount) {
logger.info("================proxy executor.update method.========");
return batchInsertData(executor, ms, metaObject, list, maxCount);
}
}
}
// not proxy
return invocation.proceed();
} private Object batchInsertData(Executor executor, MappedStatement ms, MetaObject metaObject,
List<?> dataList, int maxCount) throws SQLException {
int updateCount = 0;
List<Object> temp = new ArrayList<>();
for (int i = 0; i < dataList.size(); i++) {
if (i != 0 && i % maxCount == 0) {
metaObject.setValue(dataName, temp);
updateCount += executor.update(ms, metaObject.getOriginalObject());
temp.clear();
}
temp.add(dataList.get(i));
}
if (!temp.isEmpty()) {
updateCount += executor.update(ms, metaObject.getOriginalObject());
}
// 还原参数
metaObject.setValue(dataName, dataList);
return updateCount;
} @Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
} @Override
public void setProperties(Properties properties) {
if (properties != null) {
this.dataName = properties.getProperty("dataName", DEFAULT_DATA_NAME);
this.maxCountName = properties.getProperty("maxCountName", DEFAULT_MAX_COUNT_NAME);
}
}
}

使用

在Spring Boot项目中,如果引用了以下依赖

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

将该插件注入到容器中即可

package com.wangtao.plugin.config;

import com.wangtao.plugin.interceptor.BatchInsertInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class MybatisConfig { @Bean
public Interceptor batchInsertInterceptor() {
return new BatchInsertInterceptor();
}
}

接口层

@Mapper
public interface ExampleMapper { /**
* 批量插入
* @param exampleList 记录列表
* @param maxCount 一次最大的插入条数
* @return 成功的条数
*/
int batchInsert(@Param(BatchInsertInterceptor.DEFAULT_DATA_NAME) List<Example> exampleList,
@Param(BatchInsertInterceptor.DEFAULT_MAX_COUNT_NAME) int maxCount);
}

最新文章

  1. 初次启动app校验的活动图和分析
  2. 3dmax模型制作备忘录
  3. C#使用Graphics画圆写字
  4. AC日记——最大数 洛谷 P1198 [JSOI2008]
  5. 创建型模式(前引)简单工厂模式Simple Factory
  6. X-UniTMX:导入大型Tiled地图文件(*.tmx)到Unity3d中比较好的插件
  7. 如何避免后台IO高负载造成的长时间JVM GC停顿(转)
  8. linux内核启动流程[转]
  9. Kotlin
  10. 关于Netty的入门使用
  11. python之做一个简易的翻译器(二)
  12. phpstudy vhosts.conf 文件配置 记录下!
  13. Python学习(六) —— 函数
  14. Effective Java 第三版——71. 避免不必要地使用检查异常
  15. Java反射,参数为数组
  16. nginx反向代理proxy_set_header自定义header头无效
  17. 201621123006 《Java程序设计》第12周学习总结
  18. orderby与groupby同时使用
  19. proxyee down源码分析
  20. 【kmp算法】poj2406 Power Strings

热门文章

  1. 基于C++的OpenGL 06 之摄像机
  2. Java/.Net双平台核心,Jvm和CLR运行异同点
  3. net core api上传下载大文件 413、400错误 IIS服务器
  4. 【转】IDEA搭建SSM框架(spring+maven+mybatis+mysql+junit)
  5. word2021自带viso屏幕闪烁、抖动问题解决
  6. REDIS基础要点
  7. node、mongodb、服务器相关
  8. codeforce A. Many Equal Substrings
  9. SAP 交货单抬头客制化界面以及字段
  10. replace 常用积累