背景

有时候使用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. 达标式减量策略又一例证(STRASS研究)

    标签: 类风湿关节炎; T2T策略; TNF抑制剂; 药物减停; STRASS研究 达标式减量策略又一例证(STRASS研究): RA维持期个体化减停TNF拮抗剂是可能的 电邮发布日期: 2016年1 ...

  2. JS弹窗遮罩 POP

    html: <div class="popBox"> <div class="pb"> <span class="clo ...

  3. echarts饼图中间添加文字

    加到option配置里 title: { text: "2673682", left: "center", top: "50%", text ...

  4. postgresql 常用的删除重复数据方法

    一. 最高效方法 测试环境验证,6600万行大表,删除2200万重复数据仅需3分钟 delete from deltest a where a.ctid = any(array (select cti ...

  5. AI 能多强「GitHub 热点速览」

    不知道 AI 在你那边是什么样的具象,在我这就是各种搞图:从给线稿图上色,到直接给你生成一张小色图,AI 最近是真出风头,本周热点速览也收录了 2 个 AI 项目,也和图像有关.还有一个和 AI 相关 ...

  6. 96、nacos大量日志

    问题描述:access 日志大量打印,相关 Issue 点击这里.主要表现是: {nacos.home}/logs/access_log.2019-xx-xx.log类似格式文件名的日志大量打印,而且 ...

  7. 4. Lighting 窗口

    Lighting 实现烘焙或者实时渲染都在这里设置,其他灯光或者反射探头的作用相当于允许 Lighting (窗口)烘焙或者实时渲染. 0bject: Lightmap Static: 把烘焙的对象设 ...

  8. javaWeb学习一

    web开发(web就是网页): 静态web html.css 提供给所有人看到数据不会改变 动态web 提供给所有人看到数据会改变,不同用户.不同时间和地点都会不同 技术栈:Servlet/JSP,A ...

  9. 面了几个说自己精通 Vue 的同学,实在一言难尽……

    请说一下响应式数据的原理 默认 Vue 在初始化数据时,会给 data 中的属性使用 Object.defineProperty 重新定义所有属性,当页面到对应属性时,会进行依赖收集 (收集当前组件中 ...

  10. Mysql数据库基础第六章:变量、存储过程与函数

    Mysql数据库基础系列 软件下载地址 提取码:7v7u 数据下载地址 提取码:e6p9 mysql数据库基础第一章:(一)数据库基本概念 mysql数据库基础第一章:(二)mysql环境搭建 mys ...