mybatis 批量插入速度慢

博客讲述了在处理大量Excel数据时,从原本的嵌套循环到预分配主键和批量插入的优化过程。通过设置MySQL参数rewriteBatchedStatements和统一参数个数,实现了真正的批量插入,显著提升了效率。最后进行了数据库清理,并讨论了多线程优化的可能性,强调了MyBatis批量插入参数一致性的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 问题情况:

导入400个Excel 

每个Excel5000条数据

需要对Excel 进行小范围处理  插入三张表

原同事进行简单嵌套多层循环进行判断

因为需要副表主键进行主表关系绑定

由原来同事代码的简单嵌套循环升级为  预分配主键  进行主表附表的同时批量插入

避免多次单个插入附表等待主键返回以及数据库连接问题

操作完所有数据后用时三十小时

时间长原因分析:

主表未进行真正批量插入

解决方案一:

mysql连接增加参数  rewriteBatchedStatements=true

表示允许mysql进行批量插入

此参数默认为关闭状态,说会因为返回主键或其他造成未知错误。具体原因未深究

设置后发现插入任不是真正批量插入,依然是由循环单个sql进行插入

查看打印的sql发现多次sql的参数不一致

因参数个数不一致会造成mybatis无法解析,会使用循环插入方式解决。

解决方案二:

给所有参数设置默认值

给主表的无参构造函数设置所有默认值,在Excel对象与数据库bean对象进行拷贝时,除了读出的数据其他均保留为默认值

此举作用:让插入语句拥有统一的参数个数和顺序

让mybatis可以使用  insert into table () values ()()()()()()  的语句形式

从而实现真正的批量插入

达到  几千条/秒

当两百万数据插入完成后,进入数据库清理默认数据

update table  set a = null where a = 'defaultcvalue'

 中间优化了一些小表的小几万数据 放入内存通过map进行缓存  减少了400 * 50000 * 小表数量  的次数循环

最终插入加清理 两百万简单处理的数据 用时一个小时左右 

若使用  多线程 可能耗时更短  但是因为使用了预分配主键的问题,不想在保证数据一致性上在花费功夫   就这样吧   累了

总结:mybatis 和 mybaits plus  的批量插入需要保证 入参个数与顺序一致 否则即使打开了  rewriteBatchedStatements=true 参数也不会进行真正的批量插入

物理多线程:甚至可以使用两台计算机同时执行相同的流程的多线程方式     hhhhhhhh

学吧。学无止境啊

### 使用 MyBatis 进行 List 的批量插入MyBatis 中实现 `List` 类型的数据批量插入可以通过多种方式进行,其中最常见的是通过动态 SQL 和 Batch 模式来完成。以下是具体的实现方式: #### 方法一:使用 Dynamic SQL (`<foreach>` 标签) 这种方式利用 MyBatis 提供的 `<foreach>` 标签,在 XML 映射文件中构建动态 SQL 来执行批量插入。 ##### 配置 Mapper 文件 ```xml <insert id="batchInsert" parameterType="java.util.List"> INSERT INTO table_name (column1, column2, column3) VALUES <foreach collection="list" item="item" separator=","> (#{item.column1}, #{item.column2}, #{item.column3}) </foreach> </insert> ``` 上述代码片段展示了如何通过 `<foreach>` 构建多条记录的插入语句[^1]。每一条记录都由 `#{}` 占位符表示,并绑定到传入参数中的对象属性上。 ##### 调用示例 假设有一个实体类 `Entity` 表示要插入的对象列表,则可以这样调用: ```java public int batchInsert(List<Entity> entityList); ``` 此方法简单易懂,适合中小型数据量的操作。然而当数据量较大时可能遇到性能瓶颈或超出数据库最大允许的单次查询长度限制[^2]。 --- #### 方法二:启用 MyBatis 的 Batch Mode Batch 模式的原理是开启 JDBC 的批处理功能,减少与数据库之间的交互次数从而提升效率。具体步骤如下: ##### 开启事务支持 为了使批处理生效,需手动管理 Session 并显式提交事务。 ```java SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false); // 设置 ExecutorType 为 BATCH try { YourMapper mapper = sqlSession.getMapper(YourMapper.class); for (Entity entity : entityList) { mapper.insert(entity); // 插入单个对象 } sqlSession.commit(); // 提交事务 } finally { sqlSession.close(); } ``` 在此过程中,每次调用 `mapper.insert()` 不会立即向数据库发送请求而是缓存起来直到最后统一提交。 ##### 注意事项 - 如果发生异常需要回滚操作,应确保捕获错误并调用 `sqlSession.rollback()`. - 对于非常大的数据集建议分批次处理以免占用过多内存资源。 --- #### 性能比较及适用场景分析 | **特性** | **Dynamic SQL (<foreach>)** | **Batch Mode** | |------------------------|-----------------------------------------------|-----------------------------------------| | 数据规模 | 小至中等大小 | 大规模 | | 执行速度 | 较(受制于单次大字符串拼接) | 更快 | | 内存消耗 | 较低 | 可能较高 | | 数据库兼容性 | 支持所有主流关系型数据库 | 同样广泛支持 | 根据实际需求选择合适的方法非常重要。对于少量或者结构简单的数据推荐采用第一种方案;而对于海量高并发写入则更适合第二种技术路线。 --- ### 示例总结 无论是基于 `<foreach>` 的动态 SQL 方案还是借助 MyBatis 自带的 Batch 功能都可以很好地满足业务上的批量插入诉求。开发者应当依据项目特点权衡利弊做出最佳决策。 ```java // Java端接口定义 int batchInsert(@Param("list") List<Entity> entities); // 或者配合Batch模式下的逐条插入函数 void insert(Entity entity); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值