mysql批量插入参数取不到_Mybatis批量插入问题&MySQL参数max_allowed_packet

1、背景:

在做业务系统时,经常会碰到主子表模型,子表的数据量比较大,如果采用for循环进行insert操作,效率会很慢,MyBatis提供一个批量操作功能foreach,批量插入操作效率会大大提高。

随之而来,我们会有一个疑问,这个数据量有没有极限呢,它会受哪些条件影响?带着这样的思考我们进行实验,看看结果如何。

2、测试过程

1)数据库使用MySQL8.0.19,默认配置。数据使用虚拟机安装,虚拟机配置为2核4G内存。

2)数据库表结构

CREATE TABLE`bd_user` (

`id`bigint(0) NOT NULL,

`dept_id`bigint(0) NULL DEFAULT NULL COMMENT '部门ID',

`user_code`varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户编码',

`user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名称',

`birthday` dateNULL DEFAULT NULL COMMENT '生日',

`usable`tinyint(1) NULL DEFAULT NULL COMMENT '是否可用',PRIMARY KEY(`id`) USING BTREE) ENGINE= InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '人员' ROW_FORMAT = DYNAMIC;

3)测试代码

@SpringBootTest(classes = MybatisApplication.class)public classUserTest {

@AutowiredprivateIUserOperateService userOperateService;

@AutowiredprivateSnowFlake snowFlake;

@Testpublic voidaddUser() {int start = 0;int len = 10000;

List list = new ArrayList<>(len);for (int j = 0; j < len; j++) {

User model= newUser();

model.setId(snowFlake.nextId());

model.setDeptId((long) (1 + j % 4));

model.setUserCode(StringUtils.leftPad((++start) + "", 10, "0"));

model.setUserName("测试数据" +model.getUserCode());

model.setUsable(Boolean.TRUE);

model.setBirthday(newDate());

list.add(model);

}long startTime =System.currentTimeMillis();

userOperateService.save(list);//for (User user : list) {//userOperateService.save(user);//}

System.out.println("耗时:" + (System.currentTimeMillis() - startTime) + "毫秒");

}

}

4)实验结果如下(每次操作后数据都会被清空)

记录数

for方式耗时(毫秒)

foreach方式耗时(毫秒)

第一次

第二次

第三次

第一次

第二次

第三次

1000

4909

4923

4327

890

860

879

5000

18196

18316

18633

1350

1200

1333

10000

-

-

-

1782

1476

1398

100000

-

-

-

6567

4780

5288

500000

23691

22573

22128

数据达到100W条记录时,出现如下错误:

com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (99,899,527 > 67,108,864). You can change this value on the server by setting the 'max_allowed_packet' variable.

3、关于MySQL的max_allowed_packet参数

1)参数说明

max_allowed_packet为数据包消息缓存区最大大小,单位字节,默认值67108864(64M),最大值1073741824(1G),最小值1024(1K),参数值须为1024的倍数,非倍数将四舍五入到最接近的倍数。

数据包消息缓存区初始大小为net_buffer_length个字节

每条SQL语句和它的参数都会产生一个数据包缓存区,跟事务无关。

我尝试调整该参数的大小,它并不能提高性能,它的作用在于能够处理大参数,如大BLOB或长字符串就可能调整该参数,还有in后面的记录数也受制于该参数。

2)查看和设置max_allowed_packet参数

show variables like 'net_buffer_length';

show variableslike 'max_allowed_packet'; //查看参数set global max_allowed_packet=536870912; // 重新打开数据库连接参数生效,数据库服务重启后参数恢复为默认,想持久化可以在my.cnf中设置该参数

4、回到刚才的报错

刚才我们测试100W条数据报错,如果我们把100W数据拆成2个50W条数据进行保存,则不会报错,耗时大约为插入50条数据的的2倍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于MybatisMySQL批量插入和批量更新,可以使用以下方法: 1. 批量插入 使用MyBatis的foreach标签,可以很方便地实现批量插入操作。示例如下: ```xml <insert id="batchInsert" parameterType="java.util.List"> insert into my_table (col1, col2, col3) values <foreach collection="list" item="item" separator=","> (#{item.col1}, #{item.col2}, #{item.col3}) </foreach> </insert> ``` 其中,parameterType指定参数类型为List,collection属性指定要插入的List对象,item指定List中的元素,separator指定分隔符。 在Java代码中,调用该方法时,将List对象作为参数传入即可。 2. 批量更新 对于批量更新,可以使用MySQL的replace into语句来实现。示例如下: ```xml <update id="batchUpdate" parameterType="java.util.List"> <foreach collection="list" item="item" separator=";"> replace into my_table (id, col1, col2, col3) values (#{item.id}, #{item.col1}, #{item.col2}, #{item.col3}) </foreach> </update> ``` 其中,replace into语句会先尝试插入记录,如果记录已存在,则更新记录。参数类型和调用方式与批量插入相同。 3. 存在即更新 如果只想更新已存在的记录,可以使用MySQL的on duplicate key update语句。示例如下: ```xml <update id="updateIfExists" parameterType="com.example.MyEntity"> insert into my_table (id, col1, col2, col3) values (#{id}, #{col1}, #{col2}, #{col3}) on duplicate key update col1 = values(col1), col2 = values(col2), col3 = values(col3) </update> ``` 其中,id字段为主键。如果该记录已存在,则更新col1、col2、col3字段;否则插入新记录。参数类型为MyEntity,调用方式为传入一个MyEntity对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值