Maison >Java >javaDidacticiel >Comment utiliser springboot+mybatis pour insérer rapidement de grandes quantités de données
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')...
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.
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.
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
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>
@SpringBootApplication //引导类核心注解 @EnableScheduling //开启定时任务 public class BatchApplication { public static void main(String[] args) { SpringApplication.run(BatchApplication.class,args); } }
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 # 别名
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
Remarque : l'efficacité de MyISAM sera augmenter plus rapidement qu'INNODB.
@Data
public class User {
private int id;
private String username;
private String pwd;
private int sex;
private LocalDate birthday;
}
5. Mappeur de couche de persistance et fichier de mappage
@Mapper
public interface UserMapper {
void insertBatch(@Param("userList") List<User> userList);
}
<?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>
6.
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 ;7. util pour générer des objetsNous 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.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()); } } } }
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; } }
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; } }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!