广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >Mybatis批量插入数据的两种方式
  • 454
分享到

Mybatis批量插入数据的两种方式

mybatisjava开发语言batchinsert 2023-09-07 16:09:19 454人浏览 独家记忆
摘要

总体描述 软件开发过程中需要批量插入数据的场景有几种: 从离线文件(excel, csv等)导入大批量数据到系统。从其它系统定时或者人工同步大批量数据到系统。程序自身的某些算法执行时会生成大批量数据保

总体描述

软件开发过程中需要批量插入数据的场景有几种:

  1. 从离线文件(excel, csv等)导入大批量数据到系统。
  2. 从其它系统定时或者人工同步大批量数据到系统。
  3. 程序自身的某些算法执行时会生成大批量数据保存到数据库

上面这些场景都是长时间的处理过程,在软件设计时需要将其设计成带进度展示的异步任务(同步任务微服务Http请求超时的风险)。异步任务可以使用消息框架

使用批量插入技术能提升数据持久化的性能。用mybatis有两种批量插入数据的方式可选:1. 拼接批量插入多条数据的sql. 2. 使用Batch Insert技术。

方式一:拼接插入多条数据的SQL

mapper接口代码

        void insertDataList(@Param("list") List<BatchData> dataList);

XML文件配置

    <insert id="batchInsertData" useGeneratedKeys="true" keyColumn="id" keyProperty="id">        INSERT INTO t_batch_data (            column1,            column2,            column3,            column4,            column5,            column6,            column7,            column8,            column9,            column10        ) VALUES        <foreach item="data" collection="list" separator=",">            (                #{data.column1},                #{data.column2},                #{data.column3},                #{data.column4},                #{data.column5},                #{data.column6},                #{data.column7},                #{data.column8},                #{data.column9},                #{data.column10}            )        foreach>    insert>

可以看到,XML配置文件使用 foreach 对多条数据做了拼接,Value部分用逗号分隔。拼接后的SQL样式:

INSERT INTO t_batch_data (            column1,            column2,            column3,            column4,            column5,            column6,            column7,            column8,            column9,            column10        ) VALUES                      (                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?            )         ,             (                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?            )         ,             (                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?,                ?            )

可以看到,拼接的SQL长度跟批量插入数据的条数和单条数据的字段数相关。对于像postgres这样限定了参数个数的数据库,需要提前对大批量数据做拆分处理。

下面的示例代码对批量数据按200条一组做拆分,然后再入库。

    public long foreachBatchInsert(@PathVariable("amount") int amount) {        long beginTime = System.currentTimeMillis();        List<BatchData> dataList = buildDataList(amount);        // 大数据分批处理入库        List<List<BatchData>> dataGroup = ListUtil.splitList(dataList, 200);        for (List<BatchData> group : dataGroup) {            batchInsertMapper.insertDataList(group);        }        return System.currentTimeMillis() - beginTime;    }

方式二: 使用Batch Insert技术

Mapper接口代码

        void insertData(@Param("data") BatchData data);

XML文件配置

    <insert id="insertData" useGeneratedKeys="true" keyProperty="data.id" keyColumn="id">        INSERT INTO t_batch_data (            column1,            column2,            column3,            column4,            column5,            column6,            column7,            column8,            column9,            column10        ) VALUES (            #{data.column1},            #{data.column2},            #{data.column3},            #{data.column4},            #{data.column5},            #{data.column6},            #{data.column7},            #{data.column8},            #{data.column9},            #{data.column10}        )    insert>

映射实例接口和SQL代码与插入单个对象无异。关键代码在应用层。

应用层代码

    public long mybatisBatchInsert(@PathVariable("amount") int amount) {        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false);        long beginTime = System.currentTimeMillis();        try {            BatchInsertMapper insertMapper = session.getMapper(BatchInsertMapper.class);            List<BatchData> dataList = buildDataList(amount);            for (BatchData data : dataList) {                insertMapper.insertData(data);            }            session.commit();            session.clearCache();        } catch (Exception e) {            session.rollback();        } finally {            session.close();        }        return System.currentTimeMillis() - beginTime;    }

查看打印出执行的SQL语句:

INSERT INTO t_batch_data (            column1,            column2,            column3,            column4,            column5,            column6,            column7,            column8,            column9,            column10        ) VALUES (            ?,            ?,            ?,            ?,            ?,            ?,            ?,            ?,            ?,            ?        )

拦截StatementHandler的prepare执行方法,可以看到只执行了一次预编译。批量插入不会出现参数个数超限或者SQL语句超长的问题。

对比分析

性能对比

在postgres数据库中新建了一个包含10个text类型字段的表(t_batch_data)验证了一下,插入20万条数据时间都在15秒左右,相差不大。方案1必须做分组(参数个数超过限制);方案二本身是调用的mapper的插入单个对象的接口, 不需要做分批。

应用场景分析

如表字段是固定的,字段数量也不大可以使用方案一;如表字段数量不固定(元数据驱动)推荐使用第二种方案。第二种方案在代码执行到session.commit()时数据才真正入库,如果在这之前使用数据库的数据或者回填的自增ID是有问题的。

实际产品开发过程中,即使采用第二种方案也建议对大数量做分组处理,将单次操作数据库的时间控制在2秒以内。

Demo代码地址: https://github.com/ylforever/elon-postgres.git

来源地址:https://blog.csdn.net/ylforever/article/details/126592028

--结束END--

本文标题: Mybatis批量插入数据的两种方式

本文链接: https://www.lsjlt.com/news/398514.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作