for ループを使用してデータを 1 つずつ挿入し、この挿入と同様の挿入 SQL を生成します。 user(name,pwd) value('aa','123 ' ),('cc','123')...
この解決策の利点は次のとおりです。 JDBC PreparedStatement にはプリコンパイル機能があり、プリコンパイル後にキャッシュされます。その後、SQL の実行が高速になり、JDBC によるバッチ処理が可能になり、このバッチ処理の実行は非常に強力です。
欠点は、多くの場合、SQL サーバーとアプリケーション サーバーが同じではないため、ネットワーク IO を考慮する必要があることです。ネットワーク IO に時間がかかると、SQL の実行が遅くなる可能性があります。
このオプションの利点は、ネットワーク IO が 1 つだけであることです。シャーディングでもネットワーク IO は数回しかないため、このソリューションではネットワーク IO にそれほど多くの時間を費やすことはありません。
もちろん、この解決策には欠点もあります。まず、SQL が長すぎるため、シャーディング後にバッチ処理が必要になる場合があります。第 2 に、PreparedStatement の事前コンパイルの利点を十分に活用できず、SQL を再解析する必要があり、再利用できません。第 3 に、最終的に生成される SQLは長すぎるため、データベース管理者がそれを解析する必要があり、このような長い SQL も時間がかかります。
次に 2 番目のソリューションを使用して実装します。
挿入効率を高めたい場合は、1 つずつ挿入することはできません。foreach バッチ挿入を使用する必要があります。
パフォーマンスを向上させるために、非同期挿入にマルチスレッドを使用します。
一度に複数の挿入を送信することは不可能です。多数の挿入操作は非常に時間がかかり、短時間では完了できません。これを達成するには、タイミング タスクを使用できます。
次に、コードを使用して実装する方法について説明します。
このケースは主に、mybatis を統合した SpringBoot に基づいて実装されています。
<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
注: MyISAM の効率は INNODB よりも高速になります。
User.java
@Data public class User { private int id; private String username; private String pwd; private int sex; private LocalDate birthday; }
UserMapper.java
@Mapper public interface UserMapper { void insertBatch(@Param("userList") List<User> userList); }
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>
SpringBoot はデフォルトでスケジュールされたタスクを統合します。使用手順は次のとおりです:
ブート時 @EnableScheduling アノテーションをクラスに追加して、スケジュールされたタスクを有効にします。
@Scheduled アノテーションをビジネス層メソッドに追加して、cron 式の定期的な実行を定義します。
ビジネス層メソッドで開始されるスレッドは、現在のマシン構成に応じて変更できます。ここでは 7 つのスレッドを開き、各スレッドは 20 ループを実行し、一度に 5,000 個のデータを追加します。ここで、mybatis がバッチ挿入する場合、エラーが 10,000 を超えることは推奨されないことに注意してください。データ量が多すぎるため、スタックメモリのオーバーフローが発生しやすくなります。
@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 コア スレッドの数、スレッド プール内で保証されるスレッドの最小数。
mainumPoolSize は、スレッドの最大数、つまりスレッド プール内で実行できるスレッドの最大数です。
keepAliveTime は、スレッドがアイドル状態になるまでの生存時間を保証します。スレッドをリサイクルするため;
unit は keepAliveTime (時間単位) と組み合わせて使用されます;
workQueue 作業キューは、タスクが実行される前にタスクを保存するために使用されます。
@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; } }
##
以上がspringboot+mybatis を使用して大量のデータをすばやく挿入する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。