Mybatis大数据量批量写优化的方法是什么(mybatis,开发技术)

时间:2024-02-22 06:37:53 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

Mybatis 大数据量批量写优化

在项目中使用批量数据插入,经常会用到 mybatis的 foreach,如下:

<insertid="batchInsert"parameterType="java.util.List">insertintoUSER(id,name)values<foreachcollection="list"item="model"index="index"separator=",">(#{model.id},#{model.name})</foreach></insert>

就是将

INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");

转换成

INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2"),("data1","data2"),("data1","data2"),("data1","data2"),("data1","data2");

从理论上将,复用conn,将多次io,转换成一次io,应该是提升效率的。但是实际上当数据量比较大的时候,用foreach效率非常低,速度非常慢

当表的列数较多(20+),以及一次性插入的行数较多(5000+)时,整个插入的耗时十分漫长,达到了14分钟,这是不能忍的

那为什么使用使用foreach效率如此之低呢??

Mybatis默认执行器类型为Simple,默认会为每一个sql产生一个PrepareStatement,而且对于foreach无法使用缓存。如果字段和行数非常多,那么sql必然也会很长,占位符也会非常多,除此之外还要建立占位符和参数之间的映射,那么解析时间必然会长。因此如果values行数越多,那么解析时间必然很长。执行效率低。

Mybatis大数据量批量写优化的方法是什么


如果非要使用 foreach 的方式来进行批量插入的话,可以考虑减少一条 insert 语句中 values 的个数,最好能达到上面曲线的最底部的值,使速度最快。一般按经验来说,一次性插20~50行数量是比较合适的,时间消耗也能接受。

那么如果要用批量插入,改如何优化呢?

SqlSessionsession=sqlSessionFactory.openSession(ExecutorType.BATCH);try{SimpleTableMappermapper=session.getMapper(SimpleTableMapper.class);List<SimpleTableRecord>records=getRecordsToInsert();//notshownBatchInsert<SimpleTableRecord>batchInsert=insert(records).into(simpleTable).map(id).toProperty("id").map(firstName).toProperty("firstName").map(lastName).toProperty("lastName").map(birthDate).toProperty("birthDate").map(employed).toProperty("employed").map(occupation).toProperty("occupation").build().render(RenderingStrategy.MYBATIS3);batchInsert.insertStatements().stream().forEach(mapper::insert);session.commit();}finally{session.close();}

基本思想是将 MyBatis session 的 executor type 设为 Batch ,然后通过遍历多次执行插入语句

就类似于JDBC的下面语句一样。

Connectionconnection=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true","root","root");connection.setAutoCommit(false);PreparedStatementps=connection.prepareStatement("insertintotb_user(name)values(?)");for(inti=0;i<stuNum;i++){ps.setString(1,name);ps.addBatch();}ps.executeBatch();connection.commit();connection.close();

附录:Mybatis批量处理优化

Mybatis内置的ExecutorType有3种,默认的是simple单句模式,该模式下它为每个语句的执行创建一个新的预处理语句,单句提交sql;batch模式重复使用已经预处理的语句,并且批量执行所有语句,大批量模式下性能更优。

请注意batch模式在Insert操作时事务没有提交之前,是没有办法获取到自增的id,所以请根据业务情况使用。
使用simple模式提交10000条数据,时间为19s,batch模式为6s ,大致情况如此,优化的具体还要看提交的语句情况。
如果需要使用 foreach来优化数据插入的话,需要将每次插入的记录控制在 10-100 左右是比较快的,建议每次100来分割数据,也就是分而治之思想。

普通插入

默认的插入方式是遍历insert语句,单条执行,效率肯定低下,如果成堆插入,更是性能有问题。

INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2");

foreach 优化插入

如果要优化插入速度时,可以将许多小型操作组合到一个大型操作中。理想情况下,这样可以在单个连接中一次性发送许多新行的数据,并将所有索引更新和一致性检查延迟到最后才进行。

<insertid="batchInsert"parameterType="java.util.List">insertintotable1(field1,field2)values<foreachcollection="list"item="t"index="index"separator=",">(#{t.field1},#{t.field2})</foreach></insert>

翻译成sql语句也就是

INSERTINTO`table1`(`field1`,`field2`)VALUES("data1","data2"),("data1","data2"),("data1","data2"),("data1","data2"),("data1","data2");
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:Mybatis大数据量批量写优化的方法是什么的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:MyBatis模糊查询的实现方式有哪些下一篇:

7 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18