“This is the 7th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Before talking about the function optimization I have done, I said the optimization of address book synchronization. For details, see the optimization of address book synchronization efficiency. I mentioned using Mybatis to insert data in batches, and insert the upper limit of 10,000 data into the table at a time. The interviewer had some questions about the one-time insertion of 10,000 pieces of data, and thought that such a large number of data could not be inserted. However, I did succeed in this function, and I was not sure about the specific upper limit of the one-time insertion, so I found time to do the following experiment.

Firstly, I set up SpringBoot+Mybatis project test by myself, and the steps are as follows

1. Build test projects

Idea constructs SpringBoot+MyBatis project

Gitee code: https://gitee.com/AJiSun/SpringBoot-MyBatis

File->New->Project

Dependencies: select a mysql dependency if you don’t want to add it to poM

Add the required POM

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2. 0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
Copy the code

Then it is to create a new folder, create the required files, my directory structure is as follows

Configuration in application.yml

server:
port: 7070
spring:
application:
  name: ajisun-mybatis
datasource:
  driver-class-name: com.mysql.jdbc.Driver
  url: jdbc:mysql://localhost:3306/ajisun_mybatis? useUnicode=true&characterEncoding=utf-8&useSSL=false&useInformationSchema=true
  username: root
  password: root

mybatis:
mapperLocations: classpath:mapper/*.xml
typeAliasesPackage: com.ajisun.coding.ajisunmybatis.entity
 # Enable hump naming
configuration:
    map-underscore-to-camel-case: true
Copy the code

Add annotation @mapperscan to the startup class (mapper can be scanned at startup)

@SpringBootApplication
@MapperScan("com.ajisun.coding.ajisunmybatis.mapper")
public class AjisunMybatisApplication {
public static void main(String[] args) { SpringApplication.run(AjisunMybatisApplication.class, args); }}Copy the code

Content in an entity class

public class SyncEmployee implements Serializable {
   private Long syncId;
   private Long syncCode;
   private String employeeNum;
   privateString imageUrl; ./ / set/get omitted
}
Copy the code

Mapper. In Java

public interface SyncEmployeeMapper {
   /** * query list *@return* /
   List<SyncEmployee> selectList(a);
}
Copy the code

Mapper XML content

<? xml version="1.0" encoding="UTF-8"? > <! DOCTYPE mapper PUBLIC"- / / mybatis.org//DTD Mapper / 3.0 / EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
​
<mapper namespace="com.ajisun.coding.ajisunmybatis.mapper.SyncEmployeeMapper">
   <select id="selectList" resultType="com.ajisun.coding.ajisunmybatis.entity.SyncEmployee">
      SELECT * FROM sync_employee;
   </select>
</mapper>
Copy the code

Contents of the Interface Service class

public interface SyncEmployeeService {
   /** * query list *@return* /
   List<SyncEmployee> selectList(a);
}
Copy the code

The contents of the class that implements the Interface Service

The @service annotation indicates that the class is a Service and will be scanned by SpringBoot.

@Service
public class SyncEmployeeServiceImpl implements SyncEmployeeService {
​
   @Autowired
   private SyncEmployeeMapper syncEmployeeMapper;
​
   /** * query list *@return* /
   @Override
   public List<SyncEmployee> selectList(a) {
       return syncEmployeeMapper.selectList();
  }
Copy the code

Contents of the interface file controller

@RestController
@RequestMapping("/user")
public class SyncEmployeeController {
​
   @Autowired
   private SyncEmployeeService syncEmployeeService;
​
   @GetMapping("/list")
   public ResponseEntity<List<SyncEmployee>>  list(){
       returnResponseEntity.ok(syncEmployeeService.selectList()); }}Copy the code

At this point you can start the port is configured in the yml 7070, access interface is [get] HTTP: / / http://localhost:7070/user/list

2. Build data and test

1. The table structure
CREATE TABLE `ajisun_mybatis`.`sync_employee`  (
  `sync_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `sync_code` bigint(30) NOT NULL COMMENT 'Synchronize batch number',
  `employee_num` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'Employee Code',
  `name` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'Name of Employee',
  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT 'the tenant ID',
  `email` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'Email',
  `mobile` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'Mobile phone',
  `inter_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT International code,
  `code_mobile` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'International code + Mobile number',
  `gender` tinyint(4) NULL DEFAULT NULL,
  `cid` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'Identity code',
  `status` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'Employee status',
  `enabled_flag` tinyint(1) NULL DEFAULT NULL COMMENT 'Enabled status',
  `entry_date` datetime(0) NULL DEFAULT NULL COMMENT 'Staff Entry Time',
  `birthday` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT Date of birth,
  `ldap_flag` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'No Ldap user',
  `password` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'password',
  `image_url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'avatar',
  `sync_status` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'the sync status',
  `sync_message` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT 'the sync information'.PRIMARY KEY (`sync_id`) USING BTREE,
  INDEX `sync_emp_n1`(`sync_code`, `tenant_id`) USING BTREE,
  INDEX `sync_emp_n2`(`email`, `sync_code`, `tenant_id`) USING BTREE,
  INDEX `sync_emp_n3`(`mobile`, `sync_code`, `tenant_id`) USING BTREE,
  INDEX `sync_emp_n4`(`employee_num`, `tenant_id`, `sync_code`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = 'Employee Synchronization Intermediate Table' ROW_FORMAT = Dynamic;
Copy the code

Add method to springBoot-Mybatis project (reference code, here only the main places)

Mapper. XML batch insert code
<insert id="batchInsertData">
      insert into sync_employee (sync_id,sync_code,employee_num,name,tenant_id, email,mobile,inter_code,code_mobile,gender,cid,status,enabled_flag, entry_date,birthday,ldap_flag,image_url,sync_status,sync_message)
      values
       <foreach collection="syncEmployeeList" item="sync" separator=",">
          (
          #{sync.syncId},
          #{sync.syncCode},
          #{sync.employeeNum},
          #{sync.name},
          #{sync.tenantId},
          #{sync.email},
          #{sync.mobile},
          #{sync.interCode},
          #{sync.codeMobile},
          #{sync.gender},
          #{sync.cid},
          #{sync.status},
          #{sync.enabledFlag},
          #{sync.entryDate},
          #{sync.birthday},
          #{sync.ldapFlag},
          #{sync.imageUrl},
          0,
          #{sync.syncMessage}
          )
       </foreach>
   </insert>
Copy the code
3. Code in service (loop the amount of data needed)
@Override
   public void batchInsertData(Long syncCode) {
       List<SyncEmployee> syncEmployeeList = new ArrayList<SyncEmployee>();
       for (int i=10000; i<20000; i++){ SyncEmployee ee =new SyncEmployee();
           ee.setSyncId(Long.valueOf(i));
           ee.setSyncCode(syncCode);
           ee.setEmail(i+"@qq.com");
           ee.setMobile("121000"+String.valueOf(+i));
           ee.setCodeMobile(ee.getInterCode()+"-"+ee.getMobile());
           ee.setEmployeeNum("ajisun"+i);
           ee.setEnabledFlag(1);
           ee.setGender(i%2);
           ee.setImageUrl("Http://ajisun.com/'s head. PNG");
           ee.setName(i+"");
           ee.setLdapFlag(i%2);
           ee.setEntryDate(new Date());
           ee.setStatus("ON");
           ee.setTenantId(0L);
           ee.setBirthday("1900-01-01");
           ee.setSyncMessage("new data "+i);
           syncEmployeeList.add(ee);
      }
       long start = System.currentTimeMillis();
       syncEmployeeMapper.batchInsertData(syncEmployeeList);
       long end = System.currentTimeMillis();
       System.out.println(end-start);
  }
Copy the code
4. After preparations are complete, start the operation

The above method is used to construct 10,000 pieces of data at a time, and then batch insert through SQL

com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (4,879,714 > 4,194,304). You can change this valueon the server by setting the 'max_allowed_packet' variable.
Copy the code

Error: Error: the size of 10000 data is larger than the limit of mysql, but there is no problem with the development environment (check the development environment and the value is really large)

Check the size of max_allowed_packet in the current environment. The default size of the following version is 4M

mysql> show global variables like 'max_allowed_packet'; +--------------------+---------+ | Variable_name | Value | +--------------------+---------+ | max_allowed_packet | 4194304 | + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - + -- -- -- -- -- -- -- -- -- + 1 row in the set (0.01 SEC) mysql > select 4194304/1024/1024; + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 4194304/1024/1024 | | + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + | | 4.00000000 + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 1 row in the set (0.00 SEC)Copy the code

Make this parameter larger (10M)

mysql> set global max_allowed_packet = 1024*1024*10; Query OK, 0 rows affected (0.01sec)Copy the code

The set command is temporary and needs to open a new session to take effect, restart the SpringBoot service and invoke the interface. Max_allowed_packet = 1024* 1024*10 you can also modify the mysql configuration file to make it permanent.

You can also modify the mysql configuration file to make it permanent max_allowed_packet = 1024* 1024*10

Calling the interface again succeeds

Continue to increase the amount of operation data, modify the loop condition (30,000 data), the total size of the data is about 14M

com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (14,637,233 > 10,485,760). You can change this value on the server by setting the 'max_allowed_packet' variable.
Copy the code

The same max_allowed_packet error occurred as above, and the size of the packet exceeded the value of max_allowed_packet.

Therefore, after testing, it can be determined that how much data Mybatis can insert depends on mysql’s max_allowed_packet size limit, rather than its own limit.

3. Summary

This paper focuses on testing whether Mybatis has an impact on the volume of data inserted in batches, and it is found that it does not. It is mainly the limitation of mysql itself on the received data volume, which is controlled by parameter max_allowed_packet.

However, it is important to pay attention to efficiency problems when using Mybatis large data volume batch insert. This method is only tested and not recommended.


I am Mr. Ji, with output force input and continue to learn, continue to share technology series articles, as well as the whole network worth collecting good articles, welcome to pay attention to or pay attention to the public number, to be a continuous growth of technical people.

4. Historical articles in the practical issues series

(Also check out the Nuggets section.)

1. Easy tools: slow SQL analysis pt-query-digest;

2. Easy to use: pt-online-schame-change;

3. How to prevent messages from being whoring;

4. Use double index skillfully to avoid the problem that es index does not exist;

5. If the problem cannot be reproduced locally, debug it online.

6. Optimize the data synchronization efficiency of the organizational structure and speed up by 100 times;