背景

有时候使用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插件-分批次插入数据的更多相关文章

  1. 使用mybatis向oracle数据库插入数据异常

    遇到了使用mybatis向oracle数据库插入数据异常的问题, 具体的报错如下:org.springframework.jdbc.UncategorizedSQLException: ### Err ...

  2. MyBatis在Oracle中插入数据并返回主键的问题解决

    引言:  在MyBatis中,希望在Oracle中插入数据之时,同一时候返回主键值,而非插入的条数... 环境:MyBatis 3.2 , Oracle. Spring 3.2   SQL Snipp ...

  3. [oracle] 如何使用myBatis在数据库中插入数据并返回主键

    在MyBatis中,希望在Oracle中插入数据的同时返回主键值,而非插入的条数. ① oracle使用 selectKey. U_USER_INFO_SEQ 是在数据库中定义好的这张表关联的序列se ...

  4. Mybatis使用generatedKey在插入数据时返回自增id始终为1,自增id实际返回到原对象当中的问题排查

    今天在使用数据库的时候,遇到一个场景,即在插入数据完成后需要返回此数据对应的自增主键id,但是在使用Mybatis中的generatedKey且确认各项配置均正确无误的情况下,每次插入成功后,返回的都 ...

  5. mybatis使用序列批量插入数据

    mybatis只提供了单条数据的插入,要批量插入数据我们可以使用循环一条条的插入,但是这样做的效率太低下,每插入一条数据就需要提交一次,如果数据量几百上千甚至更多,插入性能往往不是我们能接受的,如下例 ...

  6. Mybatis中,当插入数据后,返回最新主键id的几种方法,及具体用法

    insert元素 属性详解 其属性如下: parameterType ,入参的全限定类名或类型别名 keyColumn ,设置数据表自动生成的主键名.对特定数据库(如PostgreSQL),若自动生成 ...

  7. 基于mybatis向oracle中插入数据的性能对比

    数据库表结构: 逐条插入sql语句: <insert id="insert" parameterType="com.Structure"> INSE ...

  8. mybatis注解方式批量插入数据

    @Insert("<script>" + "INSERT INTO cms_portal_menu(name,service_type,index_code) ...

  9. Mybatis + Mysql 插入数据时中文乱码问题

    近日跟朋友一起建立一个项目,用的是spring+mybatis+mysql. 今天碰到一个mybatis向mysql中插入数据时,中文显示为'???'的问题,拿出来说下. 对于数据库操作中出现的中文乱 ...

  10. 分批插入数据基于mybatis

    DB框架:Mybatis.DataBase:Oracle. ---------------------------------------------------------------------- ...

随机推荐

  1. P6329 【模板】点分树 | 震波

    \(\text{Solution}\) 点分树就是将点分治过程中的重心连成一棵虚树 对点分树子树信息的记录,就是点分治处理每个重心时需要的信息 这样就可以留下点分治的过程,支持多次修改和查询 点分树树 ...

  2. MyBatis 查询的条目与预期的不一致

    预期查询的数据条目是 4 条: 但是 MyBatis 查询出来的结果只有 2 条数据: resultMap 开启了 autoMapping 功能,就不需要多余地添加 result.下面是错误的映射操作 ...

  3. Vue props配置项(属性)

    功能:让组件接收外部传过来的数据 1.传递数据: <Demo name="XXX"/> 2.接收数据: (1)第一种方式(只接收): props:['name'] (2 ...

  4. WPF CommandParameter 传递多个参数的方法

    1.新建一个按钮内容如下 <Button Name="btnOK" Content="确定" Height="20" Width=&q ...

  5. tasklist

    tasklist是windows下列出进程信息的指令,可配合taskKill来关毕进程 https://learn.microsoft.com/zh-cn/windows-server/adminis ...

  6. Linux环境使用Docker安装SqlServer2017

    系统环境: CentOS 7.6 64位(同样适用于Ubuntu) 安装步骤: 1.创建文件夹 /home/docker/sqlserver/mssql 2.下载镜像并用外部匿名卷挂载数据 $ doc ...

  7. vue中的Swiper使用slideTo提示no function

    参考官网资料解决:

  8. Windchill_二次开发新手入门常用的API

    Windchill_二次开发新手入门常用的API 1.根据零件名称/编码 得到该零件 wt.clients.prodmgmt.WTPartHelper.findPartByName(name) ;   ...

  9. flask中的线程隔离技术

    一.引入: 在无线程隔离情况下,通过线程调用函数,函数内部改变传入对象的属性值(排除非线程安全情况),都将更改传入的对象属性 1 import threading 2 3 class TestThre ...

  10. kafka集群under replicated分析

    近期随着业务消息量增大,现网几套kafka集群频繁收到under repliacted告警,集合近期定位分析过程,主要有以下几个方面:1. 查看是否有主机挂掉,或近期是否有主机重启,通过kafdrop ...