Mybatis插件-分批次插入数据
2024-10-21 04:05:27
背景
有时候使用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);
}
最新文章
- 初次启动app校验的活动图和分析
- 3dmax模型制作备忘录
- C#使用Graphics画圆写字
- AC日记——最大数 洛谷 P1198 [JSOI2008]
- 创建型模式(前引)简单工厂模式Simple Factory
- X-UniTMX:导入大型Tiled地图文件(*.tmx)到Unity3d中比较好的插件
- 如何避免后台IO高负载造成的长时间JVM GC停顿(转)
- linux内核启动流程[转]
- Kotlin
- 关于Netty的入门使用
- python之做一个简易的翻译器(二)
- phpstudy vhosts.conf 文件配置 记录下!
- Python学习(六) —— 函数
- Effective Java 第三版——71. 避免不必要地使用检查异常
- Java反射,参数为数组
- nginx反向代理proxy_set_header自定义header头无效
- 201621123006 《Java程序设计》第12周学习总结
- orderby与groupby同时使用
- proxyee down源码分析
- 【kmp算法】poj2406 Power Strings
热门文章
- 基于C++的OpenGL 06 之摄像机
- Java/.Net双平台核心,Jvm和CLR运行异同点
- net core api上传下载大文件 413、400错误 IIS服务器
- 【转】IDEA搭建SSM框架(spring+maven+mybatis+mysql+junit)
- word2021自带viso屏幕闪烁、抖动问题解决
- REDIS基础要点
- node、mongodb、服务器相关
- codeforce A. Many Equal Substrings
- SAP 交货单抬头客制化界面以及字段
- replace 常用积累