• MyBatis 批量插入foreach性能问题


    方式一:mybatis的foreach语句(默认执行器类型simple)

    1. <insert id="batchInsert" parameterType="java.util.List">
    2. INSERT INTO
    3. user_info(name,id)
    4. VALUES
    5. <foreach collection="list" item="item" index="index" separator="," >
    6. (
    7. #{item.name}
    8. #{item.id}
    9. </foreach>
    10. </insert>

    这种方式提升插入速度的原理是将传统的:

    1. insert into user_info (name,id) values (name,id);
    2. insert into user_info (name,id) values (name,id);
    3. insert into user_info (name,id) values (name,id);
    4. insert into user_info (name,id) values (name,id);

    转化为:

    1. insert into user_info (name,id)
    2. values (name,id),values (name,id) ,values (name,id),values (name,id);

    理想情况下,这样可以在单个连接中一次性发送许多新的数据,并将所有索引更新和一致性检查延迟到最后才进行,但是此种方式在表的列数较多(20+),以及一次性插入的行数较多(5000+)时,整体插入的耗时十分漫长

    Internally, it still generates the same single insert statement with many placeholders as the JDBC code above.

    MyBatis has an ability to cache PreparedStatement, but this statement cannot be cached because it contains  element and the statement varies depending on the parameters. As a result, MyBatis has to 1) evaluate the foreach part and 2) parse the statement string to build parameter mapping [1] on every execution of this statement.

    And these steps are relatively costly process when the statement string is big and contains many placeholders.

    [1] simply put, it is a mapping between placeholders and the parameters.

     从上述资料可知,耗时就耗在,foreach后有5000+个values,所以这个PreparedStatement特别长,包含了很多占位符,对于占位符和参数的映射尤其耗时。并且,查阅相关资料可知,values的增长与所需的解析时间,是呈指数型增长的

    所以如果非要使用foreach的方式来插入数据的话,建议一次性插入20~50的数据量是比较合适的,性能可以得到保障

    2、使用sqlSessionFactory自己开启session

    数据量大时推荐此种方式 ExecutorType.BATCH

    1. SqlSession sqlSession = shardingSqlSessionFactory.openSession( ExecutorType.BATCH,false);
    2. try {
    3. // 如要插入的业务数据
    4. List limitDetailDOList = new ArrayList();
    5. LimitDetailMapper mapper = sqlSession.getMapper( LimitDetailMapper.class );
    6. limitDetailDOList.forEach(mapper ::insert);
    7. sqlSession.commit();
    8. } finally {
    9. sqlSession.close();
    10. }
    11. // mapper 接口
    12. public interface LimitDetailMapper {
    13. int insert(LimitDetailDO limitDetailDO);
    14. }
  • 相关阅读:
    开开心心带你学习MySQL数据库之节尾篇
    字符串常量池与StringBuilder
    【MySQL入门到精通-黑马程序员】MySQL基础篇-DCL
    vue3使用箭头函数导入异步组件报错Invalid VNode type: undefined的解决方案
    API自动化(七)
    使用ZooKeeper客户端原生API实现分布式配置中心
    echarts三柱图叠加三柱图解法
    苹果电脑如何清理最近打开的文稿记录 Mac如何移除浏览痕迹保护隐私
    【数学建模学习笔记【集训十天】之第二天】
    Error: Google Play requires that apps target API level 26 or higher. 两种解决办法
  • 原文地址:https://blog.csdn.net/qq_36042938/article/details/126545381