背景

有时候使用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. Shell命令-常用操作

    Shell基础 1 Shell命令的基本格式 基本格式 command [选项] [参数] []表示可选的,也就是可有可无.有些命令不写选项和参数也能执行,有些命令在必要的时候可以附带选项和参数. 短 ...

  2. fastai fit_one_cycle AttributeError: 'function' object has no attribute 'parameters'

    初学fastai   fit_one_cycle语句报错指向614行, 即: return [p for p in m.parameters() if p.requires_grad] 在以前遇到这种 ...

  3. 【转载】Python(cx_oracle)的DPI-1047错误

    转自:https://blog.csdn.net/weixin_45158749/article/details/124800132 Python(cx_oracle)的DPI-1047错误 步步 F ...

  4. spring boot 3.x 配置spring security

    参考文章:https://spring.io/guides/gs/securing-web/ 导入maven <dependency> <groupId>org.springf ...

  5. I2C接口(续一)

    I2C接口共涉及到18个寄存器,下面就来对它们进行具体分析. 先来看I2C配置寄存器CFG,下表是它的全部位结构,其地址分别为0x40050000(I2C0),0x40054000(I2C1),0x4 ...

  6. pyinstaller打包Python程序报错OSError: Python library not found: libpython3.8.so, libpython3.8m.so

    重新编译python(不影响原来安装的库文件),加入--enable-shared ./configure --prefix=/usr/local/python3 --enable-shared然后m ...

  7. [后端-python实战总结]-chapter1-python基础01

    1.1 week 1 > 密码秘文: import getpass username = input('username:') passwd = getpass.getpass('passwd: ...

  8. 前端日期控件,在设置了readonly的情况,还能选择日期的解决办法

    去掉只读和增加onclick属性: $("#date").removeAttr("readonly"); $("#date").attr(& ...

  9. 判断PC端与移动端跳转

    var mobile_bs = {   versions: function () {     var u = navigator.userAgent;     return {       trid ...

  10. iOS开发-应用评分引导

    导入头文件#import <StoreKit/StoreKit.h>+ (void)yoStoreReview{ if (@available(iOS 10.3, *)) { if ([S ...