Mybatis插件-分批次插入数据
背景
有时候使用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);
}
Mybatis插件-分批次插入数据的更多相关文章
- 使用mybatis向oracle数据库插入数据异常
遇到了使用mybatis向oracle数据库插入数据异常的问题, 具体的报错如下:org.springframework.jdbc.UncategorizedSQLException: ### Err ...
- MyBatis在Oracle中插入数据并返回主键的问题解决
引言: 在MyBatis中,希望在Oracle中插入数据之时,同一时候返回主键值,而非插入的条数... 环境:MyBatis 3.2 , Oracle. Spring 3.2 SQL Snipp ...
- [oracle] 如何使用myBatis在数据库中插入数据并返回主键
在MyBatis中,希望在Oracle中插入数据的同时返回主键值,而非插入的条数. ① oracle使用 selectKey. U_USER_INFO_SEQ 是在数据库中定义好的这张表关联的序列se ...
- Mybatis使用generatedKey在插入数据时返回自增id始终为1,自增id实际返回到原对象当中的问题排查
今天在使用数据库的时候,遇到一个场景,即在插入数据完成后需要返回此数据对应的自增主键id,但是在使用Mybatis中的generatedKey且确认各项配置均正确无误的情况下,每次插入成功后,返回的都 ...
- mybatis使用序列批量插入数据
mybatis只提供了单条数据的插入,要批量插入数据我们可以使用循环一条条的插入,但是这样做的效率太低下,每插入一条数据就需要提交一次,如果数据量几百上千甚至更多,插入性能往往不是我们能接受的,如下例 ...
- Mybatis中,当插入数据后,返回最新主键id的几种方法,及具体用法
insert元素 属性详解 其属性如下: parameterType ,入参的全限定类名或类型别名 keyColumn ,设置数据表自动生成的主键名.对特定数据库(如PostgreSQL),若自动生成 ...
- 基于mybatis向oracle中插入数据的性能对比
数据库表结构: 逐条插入sql语句: <insert id="insert" parameterType="com.Structure"> INSE ...
- mybatis注解方式批量插入数据
@Insert("<script>" + "INSERT INTO cms_portal_menu(name,service_type,index_code) ...
- Mybatis + Mysql 插入数据时中文乱码问题
近日跟朋友一起建立一个项目,用的是spring+mybatis+mysql. 今天碰到一个mybatis向mysql中插入数据时,中文显示为'???'的问题,拿出来说下. 对于数据库操作中出现的中文乱 ...
- 分批插入数据基于mybatis
DB框架:Mybatis.DataBase:Oracle. ---------------------------------------------------------------------- ...
随机推荐
- JZOJ 3570. 【GDKOI2014】壕壕的寒假作业
解析 这道题比较水. 求最快什么时候做完作业? 如果要最快完成第i份作业,那么是i的前继那些作业都要完成之后才能够完成i,所以,为了尽快完成i,我们要把i的前继的作业全部先做完. 最慢什么时候做完作业 ...
- js实现图片选中马上显示图片名,选择后可以预览,即选即显
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- cowtransfer(奶牛快传)自动上传文件脚本—流程分析
cowtransfer(奶牛快传)自动上传文件脚本-流程分析 序言: 距离上传发文也有几天了,这几天也是将这个脚本优化了一下.如果还不清楚这个脚本的效果是怎么样的小伙伴可以看看我上篇文章.话不多说,我 ...
- ol序号并在序号加背景色
<style type="text/css"> .list {list-style-type: none;margin: 0;padding: 0 0 0 30px;} ...
- opencv-python 批量更改图像分辨率并且保留图像原有的透明度
opencv-python环境安装:https://www.cnblogs.com/technicist/p/17138657.html 案例代码(批量压缩图像分辨率为原来的一半,例如2400*139 ...
- 100、 FilenameUtils
FilenameUtils import org.apache.commons.io.FilenameUtils; 测试数据 String fileDirectory = "/D:/aa/b ...
- 项目day1 -- vscode远程连接云服务器
刚学完go的语法,本来想着找个小项目试试手,发现大佬们都是vscode ssh到云服务器上做开发的.正好看到阿里云的学生认证后可以白嫖,就先嫖了个试试手 跟着各大教程简单配置了一下阿里云,安装vsco ...
- FastAPI中声明参数为必需的三种方式
前提 有时候我们定义一些参数的时候,需要声明这个参数为必需,请求者必须传递该参数.FatstAPI中声明参数为必需的方式有三种,分别为:不设默认值. "..." 和 " ...
- SAP FBL1N屏幕增强,增加自定义的列
需求 因财务想要在查看未清和已清凭证的时候,看到是该凭证是否哪一个采购人员创建,因此新增一列创建人,关联关系是 EKKO-EBELN=BSEG-ZUONR,这里关联分配号是因为之前开发自动清账的时候做 ...
- vue 图片分页
<div class="activities phone"> <!-- 动态 --> <div class="activity" ...