Mybatis批量插入数据对比

前言

业务场景中有很多批量插入数据的场景:
比如:数据库需要造几百万条数据,又或者excel批量导入数据…
这里主要讲使用MyBatis批量导入数据的两种方式,及对比。

环境与数据准备

数据库统一使用了MySQL 5.7.31 ,JDK 1.8,关键pom依赖版本:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.2</version>
</dependency>

建表sql:

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',
  `name` varchar(16) DEFAULT NULL COMMENT '姓名',
  `phone_no` varchar(11) DEFAULT NULL COMMENT '手机号',
  `sex` char(1) DEFAULT NULL COMMENT '性别 0-女 1-男',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

循环单条插入

首先整了个“妈见打”的循环单条insert,大致代码如下

public void insert() {
    long start = System.currentTimeMillis();
    User user;
    for (int i = 0; i < 100000; i++) {
        user = new User();
        user.setName(RandomUtil.getRandomName());
        user.setPhoneNo(RandomUtil.getRandomPhone());
        user.setSex(RandomUtil.getRandomSex());
        user.setCreateTime(new Date());
        userDao.insert(user);
    }
    long end = System.currentTimeMillis();
    double second = (end - start) / 1000;
    logger.info("mybatis插入完成,耗时:{}秒", second);
}

测试结果如下:

数据10000条耗时(秒)50000条耗时(秒)100000条耗时(秒)
115.47369.741230.596
215.47367.203225.259
314.67670.805237.651
414.44672.579240.32
514.24368.3235.089
平均14.70369.726233.783

可以看到速度很慢了,不要这样写代码

使用foreach标签进行批量插入

标准的MyBatis批量插入,代码如下:

public void testMybatisInsertList() {
    long start = System.currentTimeMillis();
    User user;
    List<User> list = new ArrayList<>(500000);
    for (int i = 0; i < 100000; i++) {
        user = new User();
        user.setName(RandomUtil.getRandomName());
        user.setPhoneNo(RandomUtil.getRandomPhone());
        user.setSex(RandomUtil.getRandomSex());
        user.setCreateTime(new Date());
        list.add(user);
    }
    userDao.insertList(list);;
    long end = System.currentTimeMillis();
    double second = (end - start) / 1000;
    logger.info("mybatis插入完成,耗时:{}秒", second);
}

mapper.xml:

<insert id="insertList" useGeneratedKeys="true" keyProperty="id" parameterType="com.cybergeralt.model.User">
        INSERT INTO `user`(`name`, `phone_no`, `sex`, `create_time`) VALUES
        <foreach collection="list" item="list" index="index" separator=",">
            (#{list.name,jdbcType=VARCHAR}, #{list.phoneNo,jdbcType=VARCHAR},#{list.sex,jdbcType=VARCHAR},#{list.createTime,jdbcType=TIMESTAMP})
        </foreach>
</insert>

测试结果如下:

数据10000条耗时(秒)50000条耗时(秒)100000条耗时(秒)500000条耗时(秒)
11.0171.9122.97112.536
21.0651.923.03612.454
30.9991.9383.02411.598
40.9851.8822.96311.917
51.0181.8892.95711.868
平均1.0171.9082.9912.075

速度比想象中的快很多
ps:MySQL对语句大小有限制,我测试批量插入50000条数据的时候,就会报错:

com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (4,736,064 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.

解决:需要增大数据库配置max_allowed_packet,默认为4M。

SET GLOBAL max_allowed_packet=268435456; ##改为256M

通过对比可以看出,循环单条插入效率远低于使用foreach标签进行批量插入。
所以建议MyBatis使用foreach标签进行批量插入

转自一位大佬:https://cybergeralt.com/archives/99

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值