最近项目中有一个耗时较长的作业出现CPU占用率高的问题。insertintoUSER(id,name)values(#{model.id},#{model.name})这种方法提高批量插入速度的原理是使用传统的: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","数据2"),("数据1","数据2");在米ySqlDocs:https://dev.mysql.com/doc/refman/5.6/en/insert-optimization.html也提到了这个trick,如果想优化插入速度,可以把很多小操作合并成一个大操作比较理想在操作中,这将在单个连接中一次发送许多新数据行,并将所有索引更新和一致性检查推迟到最后。乍一看这个foreach没有问题,但是经过项目实践发现,当表的列数很大(20+),并且一次插入的行数很大(5000+),整个插入时间很长,达到了14分钟,让人受不了。还有[Data]https://stackoverflow.com/questions/19682414/how-can-mysql-insert-millions-records-fast中提到的一句话:?当然不要把ALL全部合并,如果数量很大。假设您需要插入1000行,那么不要一次插入一行。您不应该同样尝试在单个查询中包含所有1000行。而是将它分解成更小的尺寸。?它强调,当插入数量很大时,它不能一次放在一个语句中。但是为什么不能放在同一个句子里呢?为什么这个声明需要这么长时间?我检查了[数据]https://stackoverflow.com/questions/32649759/using-foreach-to-do-batch-insert-with-mybatis/40608353发现:?“InsertinsideMybatisforeachisnotbatch”,这是一个单一的(可能会变成巨大的)SQL语句并带来缺点:一些数据库如Oracle在这里不支持。在相关情况下:将有大量记录插入和数据库配置限制(默认情况下每个大约2000个参数statement)将被命中,如果语句本身变得太大,最终可能会出现DB堆栈错误。不能在mybatisXML中对集合进行迭代。只需在JavaForeach循环中执行一个简单的Insert语句。“最重要的是会话执行器类型”。SqlSessionsession=sessionFactory.openSession(ExecutorType.BATCH);for(Modelmodel:list){session.insert("insertStatement",model);}session.flushStatements();与默认的ExecutorType.SIMPLE不同,状态ment会为每条插入的记录准备一次并执行。?从[数据]https://blog.csdn.net/wlwlwlwl015/article/details/50246717可以看出默认的执行器类型是Simple,即为每条语句创建一个新的准备语句,即创建一个“PreparedStatement”对象。在我们的项目中,会持续使用批量插入的方法,而由于MyBatis无法对包含的语句使用缓存,那么在每次调用该方法时,都会重新解析SQL语句。?在内部,它仍然生成与上面的JDBC代码相同的带有许多占位符的单个插入语句。MyBatis有缓存PreparedStatement的能力,但是这条语句不能被缓存,因为它包含元素,并且语句根据.字符串以在每次执行此语句时构建参数映射[1]。当语句字符串很大并且包含很多占位符时,这些步骤是相对昂贵的过程。[1]简单的说就是占位符和参数之间的映射?从上面的[数据]http://blog.harawata.net/2016/04/bulk-insert-multi-row-vs-batch-using.html可以看出这需要时间。由于我在foreach之后有5000+个值,所以这个PreparedStatement很长,包含了很多占位符。占位符和参数之间的映射特别耗时。并且,查看相关[数据]https://www.red-gate.com/simple-talk/sql/performance/comparing-multiple-rows-insert-vs-single-row-insert-with-three-data-load-methods表明值的增长和所需的解析时间呈指数增长。因此,如果非要使用foreach方式进行批量插入,可以考虑减少一次insert语句中取值的个数,最好达到上面曲线的底部值,这样速度最快。一般根据[经验]https://stackoverflow.com/questions/7004390/java-batch-insert-into-mysql-very-slow,一次插入20~50行比较合适,耗时也可以接受。重点来了。上面说的是,如果非要用来插入,可以提高性能。其实在MyBatis文档中写批量插入的时候,推荐使用另一种方式。(可以在http://www.mybatis.org/mybatis-dynamic-sql/docs/insert.html中看到“支持批量插入”标题中的内容)SqlSessionsession=sqlSessionFactory.openSession(ExecutorType.BATCH);尝试{SimpleTableMappermapper=session.getMapper(SimpleTableMapper.class);List记录=getRecordsToInsert();//未显示BatchInsertbatchInsert=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();}即基本思路是设置MyBatissession的executor类型为“Batch”,然后多次执行insert语句。类似于JDBC的如下语句。连接connection=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插入,需要控制每次插入的记录数在20~50条左右。