Maison > Java > javaDidacticiel > le corps du texte

Comment utiliser springboot+mybatis pour insérer rapidement de grandes quantités de données

WBOY
Libérer: 2023-05-12 08:19:16
avant
1944 Les gens l'ont consulté

1. Plan d'implémentation de JDBC

Utilisez une boucle for pour insérer les données une par une ; générez un SQL d'insertion, similaire à cette insertion dans les valeurs de l'utilisateur (nom, mot de passe) ('aa', '123'),('cc ' ,'123')...

La première solution consiste à utiliser une boucle d'instruction for pour insérer :

L'avantage de cette solution est que PreparedStatement dans JDBC a une fonction de pré-compilation, et il sera mis en cache après pré-compilation. -compilation. Par la suite, l'exécution de SQL sera plus rapide et JDBC pourra permettre le traitement par lots. Cette exécution de traitement par lots est très puissante.

L'inconvénient est que souvent, notre serveur SQL et notre serveur d'applications peuvent ne pas être les mêmes, les E/S réseau doivent donc être prises en compte. Si les E/S réseau prennent du temps, cela peut ralentir l'exécution de SQL.

La deuxième option est de générer un SQL pour l'insertion :

L'avantage de cette option est qu'il n'y a qu'une seule IO réseau. Même le partitionnement ne représente que quelques E/S réseau, cette solution ne consacre donc pas trop de temps aux E/S réseau.

Bien sûr, cette solution présente aussi des inconvénients. Premièrement, le SQL est trop long et peut même nécessiter un traitement par lots après le partitionnement ; deuxièmement, les avantages de la pré-compilation de PreparedStatement ne peuvent pas être pleinement utilisés, et le SQL doit être réanalysé et ne peut pas être réutilisé. Troisièmement, le SQL final généré ; est trop long et le gestionnaire de base de données doit l'analyser. Un code SQL aussi long prend également du temps.

Nous utiliserons la deuxième solution pour la mettre en œuvre ensuite.

2. Idées d'implémentation spécifiques

Si nous voulons augmenter l'efficacité de l'insertion, nous ne pouvons certainement pas insérer un par un, nous devons utiliser foreach pour l'insertion par lots

Utiliser le multithread pour l'insertion asynchrone afin d'améliorer les performances ; Il est impossible de soumettre plusieurs insertions à la fois. Un grand nombre d'opérations d'insertion prendront beaucoup de temps et ne pourront pas être réalisées en peu de temps. Des tâches de synchronisation peuvent être utilisées pour y parvenir.

Parlons ensuite de la façon d'utiliser le code pour l'implémenter.

3. Implémentation du code

Ce cas est principalement implémenté sur la base de SpringBoot intégrant mybatis.

1. Importer des dépendances

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
Copier après la connexion

2. Créer une classe de démarrage

@SpringBootApplication  //引导类核心注解
@EnableScheduling //开启定时任务
public class BatchApplication {
    public static void main(String[] args) {
        SpringApplication.run(BatchApplication.class,args);
    }
}
Copier après la connexion

3. Fichier de configuration application.yml

server:
  port: 9999  # 指定端口号
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
    password: 123
mybatis:
  mapper-locations: classpath:mybatis/*.xml   #指定mapper映射文件路径
  type-aliases-package: com.qfedu.model  # 别名
Copier après la connexion

4. Créer une table et une classe d'entité User

Créer une table :

CREATE TABLE `user` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(30) DEFAULT NULL,
  `pwd` VARCHAR(20) DEFAULT NULL,
  `sex` INT(11) DEFAULT NULL,
  `birthday` DATETIME DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8
Copier après la connexion
Remarque : l'efficacité de MyISAM sera augmenter plus rapidement qu'INNODB.

User.java

@Data
public class User {
    private int id;
    private String username;
    private String pwd;
    private int sex;
    private LocalDate birthday;
}
Copier après la connexion
5. Mappeur de couche de persistance et fichier de mappage

UserMapper.java

@Mapper
public interface UserMapper {
    void insertBatch(@Param("userList") List<User> userList);
}
Copier après la connexion

UserMapper.xml

<?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.qfedu.mapper.UserMapper">
    <insert id="addList" parameterType="User"  >
        insert  into user (username,pwd,sex,birthday) values
        <foreach collection="list" item="item" separator=",">
            (#{item.username}, #{item.pwd}, #{item.sex}, #{item.birthday})
        </foreach>
    </insert>
</mapper>
Copier après la connexion
6.

SpringBoot intègre sched par défaut uled , utilisez Les étapes sont les suivantes :

Ajoutez l'annotation @EnableScheduling à la classe de démarrage pour activer les tâches planifiées ;

Ajoutez l'annotation @Scheduled à la méthode de couche métier pour définir l'exécution périodique de l'expression cron ;

Les threads démarrés dans la méthode de la couche métier peuvent être modifiés en fonction de la configuration actuelle de la machine. Nous avons ouvert 7 threads ici, et chaque thread exécute 20 boucles et ajoute 5 000 éléments de données à la fois. Il convient de noter ici que lors des insertions par lots mybatis, il n'est pas recommandé de dépasser 10 000 erreurs. La quantité de données étant trop importante, un débordement de la mémoire de la pile est susceptible de se produire.

@Component
public class UserServiceImpl {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    //线程池
    private ThreadPoolExecutor executor;
    @Scheduled(cron = "0/20 * * * * ?") //每隔20秒执行一次
    public void  addList(){
        System.out.println("定时器被触发");
        long start = System.currentTimeMillis();
        for (int i = 0; i < 7; i++) {
 
            Thread thread = new Thread(() -> {
                try {
                    for (int j = 0; j < 20; j++) {
                        userMapper.addList(UserUtil.getUsers(5000));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            try {
                executor.execute(thread);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
}
Copier après la connexion
7. util pour générer des objets

Nous l'utilisons pour simuler la génération de données à insérer dans le développement commercial réel, il peut s'agir de données importées depuis Excel.

public class UserUtil {
    private static Random random = new Random();
    public static List<User> getUsers(int num){
        List<User> users = new ArrayList<>();
        for (int i = 0;i<num;i++){
            User user = new User();
            user.setBirthday(LocalDate.now());
            user.setSex(random.nextInt(2));
            user.setPwd("123"+random.nextInt(100000));
            user.setUsername("batch"+random.nextInt(num));
            users.add(user);
        }
        return users;
    }
}
Copier après la connexion

8. Configuration du pool de threads

Paramètres du pool de threads :

corePoolSize nombre de threads principaux, le nombre minimum de threads à garantir dans le pool de threads

mainumPoolSize nombre maximum de threads, le nombre maximum de threads qui ; peut s'exécuter dans le pool de threads ;

keepAliveTime garantit le temps de survie, lorsque le thread est inactif, combien de temps il faudra pour recycler le thread

unit est utilisé en conjonction avec keepAliveTime, l'unité de temps

workQueue ; , utilisé pour stocker les tâches avant leur exécution.

@Configuration
public class ThreadPoolExecutorConfig {
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        //线程池中6个线程,最大8个线程,用于缓存任务的阻塞队列数5个
        ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 8, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));
        executor.allowCoreThreadTimeOut(true);//允许超时
        return executor;
    }
}
Copier après la connexion

9. Structure complète du projet

10.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal