MyBatis批量插入大量数据(1w以上)

2023-01-21 0 5,247

问题背景:只用MyBatis中foreach进行批量插入数据一次性插入超过一千条时候MyBatis开始报错项目使用技术:SpringBoot、MyBatis

批量插入碰到的问题:

java.lang.StackOverflowError: null

该问题是由于一次性插入数据1w条引起的,具体插入代码如下:

userDao.batchInsert(list);

<insert id="batchInsert" parameterType="java.util.List">
    INSERT INTO USER
    <trim prefix="(" suffix=")" suffixOverrides=",">
        ID, AGE, NAME, EMAIL
    </trim>
    SELECT A.*
    FROM
    (<foreach collection="list" index="index" item="item" separator="UNION ALL">
    SELECT
    sys_guid(), #{user.age}, #{user.name}, #{user.email}
    FROM dual
</foreach>) A
</insert>

以上的插入代码其实也是一种批量插入的方式,但是他的灵界点并不高,插入数据过多的时候,可能需要我们使用代码在一次分批。当然如果插入数据不超过5000的时候可以直接这么使用

插入1w条数据,发现出现错误,原因是数据量过大,栈内存溢出了。mybatis中直接使用foreach插入数据,就相当于将所有的sql预先拼接到一起,然后一起提交。这本身就是一种批量插入的处理方案,但是达不到我们要求。主要是插入有上限。如果需要更多的数据导入,我们需要更换一种方式来解决这个问题,mybatis中ExecutorType的使用。

mybatis中ExecutorType的使用

Mybatis内置的ExecutorType有3种,SIMPLE、REUSE、BATCH; 默认的是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优;但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的;

插入大量数据的解决方案,使用ExecutorType

为了能够高效,并且解决上述问题,我们使用ExecutorType,并分批插入。代码如下:

//我们使用的是springboot,sqlSessionTemplate是可以自己注入的
@Autowired
private SqlSessionTemplate sqlSessionTemplate;

public void insertExcelData(List<User> list) {
    //如果自动提交设置为true,将无法控制提交的条数,改为最后统一提交,可能导致内存溢出
    SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
    //不自动提交
    try {
        UserDao userDao = session.getMapper(UserDao.class);
        for (int i = 0; i < list.size(); i++) {
            userDao.insert(list.get(i));
            if (i % 400 == 0 || i == list.size() - 1) {
                //手动每400条提交一次,提交后无法回滚
                session.commit();
                //清理缓存,防止溢出
                session.clearCache();
            }
        }
    } catch (Exception e) {
        //没有提交的数据可以回滚
        session.rollback();
    } finally {
        session.close();
    }
}

userDao.insert(User user);

<insert id="insert" parameterType="com.echo.UserPo">
    insert into USER
    (id
    <if test="age != null">
        ,age
    </if>
    <if test="name != null">
        ,name
    </if>
    <if test="email != null">
        ,email
    </if>
    )
    values (
    sys_guid()
    <if test="age != null">
        ,#{age}
    </if>
    <if test="name != null">
        ,#{name}
    </if>
    <if test="email != null">
        ,#{email}
    </if>)
</insert>

这里采用的是单条插入,直接使用for循环,但是使用ExecutorType.BACTH就相当于手动提交。这也是我们需要的效果,所以我们在循环里面判断了,是否到了第400笔,如果到了第400笔就直接提交,然后清空缓存,防止溢出。这样就有效的实现了批量插入,同时保证溢出问题的不出现

:本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可, 转载请附上原文出处链接。
1、本站提供的源码不保证资源的完整性以及安全性,不附带任何技术服务!
2、本站提供的模板、软件工具等其他资源,均不包含技术服务,请大家谅解!
3、本站提供的资源仅供下载者参考学习,请勿用于任何商业用途,请24小时内删除!
4、如需商用,请购买正版,由于未及时购买正版发生的侵权行为,与本站无关。
5、本站部分资源存放于百度网盘或其他网盘中,请提前注册好百度网盘账号,下载安装百度网盘客户端或其他网盘客户端进行下载;
6、本站部分资源文件是经压缩后的,请下载后安装解压软件,推荐使用WinRAR和7-Zip解压软件。
7、如果本站提供的资源侵犯到了您的权益,请邮件联系: 442469558@qq.com 进行处理!

猪小侠源码-最新源码下载平台 Java教程 MyBatis批量插入大量数据(1w以上) https://www.20zxx.cn/463276/xuexijiaocheng/javajc.html

猪小侠源码,优质资源分享网

常见问题
  • 本站所有资源版权均属于原作者所有,均只能用于参考学习,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,建议提前注册好百度网盘账号,使用百度网盘客户端下载
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务