MyBatis批量插入几千条数据,foreach坑

1.问题原因

      主要时间消耗在往MyBatis中批量插入数据。mapper configuration是用foreach循环做的,经过项目实践发现,当表的列数较多(20+),以及一次性插入的行数较多(5000+)时,整个插入的耗时十分漫长,达到了14分钟

2.问题代码

     

          insert into USER (id, name) values

         

          (#{model.id}, #{model.name})

         

     

3.源码级别原因

        mybatis默认执行器类型为Simple,会为每个语句创建一个新的预处理语句,也就是创建PreparedStatement对象。在我们的项目中,会不停地使用批量插入这个方法,而因为MyBatis对于含有的语句,无法采用缓存,那么在每次调用方法时,都会重新解析sql语句,由于我foreach后有5000+个values,所以这个PreparedStatement特别长,包含了很多占位符,对于占位符和参数的映射尤其耗时。并且,查阅相关资料可知,values的增长与所需的解析时间,是呈指数型增长的

4.mybatis官方批量插入解决文档

      https://mybatis.org/mybatis-dynamic-sql/docs/insert.html

5.解决问题中心思想

      MyBatis session 的 executor type 设为 Batch ,然后多次执行插入语句。就类似于JDBC的下面语句一样。使用了 ExecutorType.BATCH 的插入方式,性能显著提升,不到 2s 便能全部插入完成

          Connection 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);

           PreparedStatement ps = connection.prepareStatement(

            "insert into tb_user (name) values(?)");

            for (int i = 0; i < stuNum; i++) {

                ps.setString(1,name);

                ps.addBatch();

            }

            ps.executeBatch();

            connection.commit();

            connection.close();

6.结论

      如果MyBatis需要进行批量插入,推荐使用 ExecutorType.BATCH 的插入方式,如果非要使用 的插入的话,需要将每次插入的记录控制在 20~50 左右

你可能感兴趣的:(MyBatis批量插入几千条数据,foreach坑)