栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis中 foreach 插入过多数据数据库死锁或响应超时

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis中 foreach 插入过多数据数据库死锁或响应超时

一、问题描述

项目中导入数据时,一次性导入上万条数据,再加上逻辑中对数据的各种校验造成的耗时,所以很容易造成数据库死锁或服务响应超时。之前的插入 sql 语句如下:

insert into test_table(test1, test2, test3, ...)
values
	
		(#{item.test1}, #{item.test2}, #{item.test3}, ...)
    

使用这种方式为什么会造成服务超时的情况,可以参考
https://blog.csdn.net/huanghanqian/article/details/83177178,这篇文章,解释的非常好。

二、解决方案

上述文章中,也提出了解决方案,但是由于是项目制,修改 ExecutorType 的话可能会影响其他的地方,所以我的解决方案如下,将数据分批次的插入,代码如下

// insertDataList : 要插入的原始数据
public void batchInsertMethod(List insertDataList) throws Exception {
		// 新建 linkedList 作为每次插入数据的一个临时容器
        linkedList batchInsertList = new linkedList<>();
        // 遍历原始数据,当临时容器 batchInsertList 长度为 1000 时,就插入一次,
        // 然后清空 batchInsertList
        for (Map tempMap: insertDataList) {
            batchInsertList.add(tempMap);
            if (batchInsertList.size() == 1000){
                iTestDao.insertData(batchInsertList);
                batchInsertList.clear();
            }
        }
      // 将剩余的数据也插入到表中
      iTestDao.insertData(batchInsertList);
    }

经测试,15000条数据,时间大概在 10-20s 内。另外,1000 条数据插入一次和 500 条数据插入一次,耗时几乎没有差别,可自行测试。

三、注意

数据库表中存储这么多条数据,肯定是要用到索引的,当数据插入到临时表后,往正式表同步时,我使用的是下面这种方式

insert into test_table1(test1, test2, test3, ...)
select a.test1, b.test2, c.test3
from test_a a
left join test_b on ...
left join test_c on ...
where ...

结果发现还是响应超时,那么只好把 sql 语句拿出来 explain 一下,结果发现没有走索引,造成 select 很慢,但是表结构中明明是存在索引的,经排查,问题原因在于连接表的字符集不一样,修改后,变为正常。
修改表结构的字符集 sql 如下:

alter table test_a convert to character set utf8mb4 collate utf8mb4_general_ci;

表结构添加多列唯一索引 sql 如下:

create unique index idx_name on test_a (column1, column2, ...);

四、参考链接
1.https://blog.csdn.net/huanghanqian/article/details/83177178

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/591661.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号