recherche
MaisonJavajavaDidacticielComment implémenter l'insertion par lots JDBC en Java

    1 Description

    Dans JDBC, la méthodeexecuteBatch peut exécuter plusieurs instructions DML par lots, ce qui est plus efficace que une seule instruction L'exécution de executeUpdate est beaucoup plus élevée. Quel est le principe ? Comment implémenter l'exécution par lots dans MySQL et Oracle ? Cet article vous présentera le principe derrière cela.

    2. Introduction à l'expérience

    Cette expérience se déroulera à travers les trois étapes suivantes

    a. exécution unique de jdbc dans mysql Time

    b. Enregistrez le temps nécessaire à l'exécution par lots et à l'exécution unique de jdbc dans Oracle

    c. exécution d'Oracle plsql

    # 🎜🎜#Les versions pertinentes de Java et de la base de données sont les suivantes : Java17, Mysql8, Oracle11G

    3. dans mysql et oracle respectivement

    create table t (  -- mysql中创建表的语句
        id    int,
        name1 varchar(100),
        name2 varchar(100),
        name3 varchar(100),
        name4 varchar(100)
    );
    create table t (  -- oracle中创建表的语句
        id    number,
        name1 varchar2(100),
        name2 varchar2(100),
        name3 varchar2(100),
        name4 varchar2(100)
    );

    Vous devez activer l'audit de la base de données avant l'expérience

    mysql active l'audit :

    set global general_log = 1;

    oracle active l'audit :

    alter system set audit_trail=db, extended;  
    audit insert table by scott;  -- 实验采用scott用户批量执行insert的方式

    le code java est le suivant :

    import java.sql.*;
    
    public class JdbcBatchTest {
    
        /**
         * @param dbType 数据库类型,oracle或mysql
         * @param totalCnt 插入的总行数
         * @param batchCnt 每批次插入的行数,0表示单条插入
         */
        public static void exec(String dbType, int totalCnt, int batchCnt) throws SQLException, ClassNotFoundException {
            String user = "scott";
            String password = "xxxx";
            String driver;
            String url;
            if (dbType.equals("mysql")) {
                driver = "com.mysql.cj.jdbc.Driver";
                url = "jdbc:mysql://ip/hello?useServerPrepStmts=true&rewriteBatchedStatements=true";
            } else {
                driver = "oracle.jdbc.OracleDriver";
                url = "jdbc:oracle:thin:@ip:orcl";
            }
    
            long l1 = System.currentTimeMillis();
            Class.forName(driver);
            Connection connection = DriverManager.getConnection(url, user, password);
            connection.setAutoCommit(false);
            String sql = "insert into t values (?, ?, ?, ?, ?)";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            for (int i = 1; i <= totalCnt; i++) {
                preparedStatement.setInt(1, i);
                preparedStatement.setString(2, "red" + i);
                preparedStatement.setString(3, "yel" + i);
                preparedStatement.setString(4, "bal" + i);
                preparedStatement.setString(5, "pin" + i);
    
                if (batchCnt > 0) {
                    // 批量执行
                    preparedStatement.addBatch();
                    if (i % batchCnt == 0) {
                        preparedStatement.executeBatch();
                    } else if (i == totalCnt) {
                        preparedStatement.executeBatch();
                    }
                } else {
                    // 单条执行
                    preparedStatement.executeUpdate();
                }
            }
            connection.commit();
            connection.close();
            long l2 = System.currentTimeMillis();
            System.out.println("总条数:" + totalCnt + (batchCnt>0? (",每批插入:"+batchCnt) : ",单条插入") + ",一共耗时:"+ (l2-l1) + " 毫秒");
        }
    
        public static void main(String[] args) throws SQLException, ClassNotFoundException {
            exec("mysql", 10000, 50);
        }
    }

    Quelques points à noter dans le code,

    # 🎜🎜 L'URL #mysql doit ajouter des paramètres useServerPrepStmts=true&rewriteBatchedStatements=true.

    • batchCnt représente le nombre d'instructions SQL exécutées dans chaque lot et 0 représente une exécution unique.

    • Premier test de mysql

      exec("mysql", 10000, batchCnt);
    • Mettez différentes valeurs batchCnt pour voir le temps d'exécution

    #🎜 🎜#batchCnt= 50 Nombre total d'éléments : 10000, insertion par lot : 50, consommation de temps totale : 4369 millisecondes

    batchCnt=100 Nombre total d'éléments : 10000, insertion par lot : 100, consommation de temps totale : 2598 millisecondes

    batchCnt= 200 Nombre total d'éléments : 10000, chaque lot d'insertions : 200, temps total passé : 2211 millisecondes

    batchCnt=1000 Nombre total d'éléments : 10000, chaque lot d'insertions : 1000, temps total dépensé : 2099 millisecondes
    batchCnt= 10000 Nombre total d'éléments : 10000, chaque insertion par lot : 10000, consommation de temps totale : 2418 millisecondes

    batchCnt=0 Nombre total d'éléments : 10000, insertion unique, consommation de temps totale : 59620 millisecondes

    # 🎜🎜#Voir le journal général

    batchCnt=5

    batchCnt=0

    Plusieurs conclusions peut être dessiné :

    #🎜🎜 #

    L'efficacité de l'exécution par lots est grandement améliorée par rapport à l'exécution unique.

    L'exécution par lots de MySQL réécrit en fait SQL et fusionne plusieurs insertions dans les valeurs d'insertion xx(),()... pour l'exécution.
    • Lors du changement de batchCnt de 50 à 100, le temps est fondamentalement réduit de moitié, mais lorsque la valeur est augmentée, la réduction du temps n'est pas évidente. Le temps d'exécution. peut même augmenter.
    • Raison de l'analyse :
    • Après que le client ait envoyé l'instruction SQL à exécuter au serveur de base de données, la base de données exécute le Instruction SQL et renvoyer les résultats au client. Temps total pris = temps d'exécution de la base de données + temps de transmission réseau. La réduction du nombre d’allers-retours grâce à l’exécution par lots réduit le temps de transfert réseau et donc le temps global. Cependant, lorsque batchCnt devient plus important, même si le temps de transmission sur le réseau n'est plus le principal goulot d'étranglement, la réduction du temps total ne sera pas aussi évidente. Surtout lorsque batchCnt=10 000, c'est-à-dire que les 10 000 instructions sont exécutées en même temps, le temps devient plus long. Cela peut être dû au fait que le programme et la base de données doivent demander plus de mémoire lors de la préparation de ces paramètres d'entrée, ce qui prend donc plus de temps (. Je suppose).

    Encore une chose, la valeur de batchCnt peut-elle être infinie ? Supposons que je doive insérer 100 millions d'éléments, puis-je insérer par lots 100 millions d'éléments à la fois ? Bien sûr que non, nous ne prenons pas en compte le problème d'espace de l'annulation. Premièrement, votre ordinateur ne dispose pas d'une mémoire aussi grande pour sauvegarder tous les 100 millions de paramètres d'entrée SQL à la fois. Deuxièmement, MySQL a également un paramètre max_allowed_packet à limiter. la longueur d’une seule instruction. Le maximum est de 1 Go. Lorsque l'instruction est trop longue, "Le paquet pour la requête est trop volumineux (1 773 901 > 1 599 488). Vous pouvez modifier cette valeur sur le serveur en définissant la variable 'max_allowed_packet'" sera signalé.

    Prochain testez l'oracle

    exec("oracle", 10000, batchCnt);
    Mettez différentes valeurs batchCnt pour voir le temps d'exécution

    batchCnt=50 Nombre total d'entrées : 10000, Insérez chaque lot : 50, temps total passé : 2055 millisecondes

    batchCnt=100 Nombre total d'éléments : 10000, insérez chaque lot : 100, temps total passé : 1324 millisecondes

    batchCnt=200 Nombre total d'articles : 10000, Insertion par lot : 200, consommation de temps totale : 856 millisecondes

    batchCnt=1000 Nombre total d'entrées : 10000, insertion par lot : 1000, consommation de temps totale : 785 millisecondes

    batchCnt =10000 Nombre total d'entrées : 10000, Chaque lot d'insertions : 10000, temps total passé : 804 millisecondes

    batchCnt=0 Nombre total d'éléments : 10000, insertion unique, temps total passé : 60830 millisecondes
    # 🎜🎜#

    Exécuté dans Oracle L'effet est fondamentalement le même que celui de MySQL, et l'efficacité des opérations de traitement par lots est nettement supérieure à celle d'une exécution unique. Le problème est qu'il n'existe pas de syntaxe d'insertion de valeurs xx(),()... dans Oracle, alors comment réalise-t-il l'exécution par lots ?

    Afficher la vue d'audit dba_audit_trail
    lorsque batchCnt=50 est exécuté

    从审计的结果中可以看到,batchCnt=50的时候,审计记录只有200条(扣除登入和登出),也就是sql只执行了200次。sql_text没有发生改写,仍然是"insert into t values (:1 , :2 , :3 , :4 , :5 )",而且sql_bind只记录了批量执行的最后一个参数,即50的倍数。根据awr报告可以看出,实际只执行了200次(由于篇幅限制,省略了awr截图)。那么oracle是怎么做到只执行200次但插入1万条记录的呢?我们来看看oracle中使用存储过程的批量插入。

    四、存储过程

    准备数据:

    首先将t表清空 truncate table t;

    用java往t表灌10万数据 exec("oracle", 100000, 1000);

    创建t1表 create table t1 as select * from t where 1 = 0;

    以下两个过程的意图一致,均为将t表中的数据导入t1表。nobatch是单次执行,usebatch是批量执行。

    create or replace procedure nobatch is
    begin
      for x in (select * from t)
      loop
        insert into t1 (id, name1, name2, name3, name4)
        values (x.id, x.name1, x.name2, x.name3, x.name4);
      end loop;
      commit;
    end nobatch;
    /
    create or replace procedure usebatch (p_array_size in pls_integer)
    is
      type array is table of t%rowtype;
      l_data array;
      cursor c is select * from t;
    begin
      open c;
      loop
        fetch c bulk collect into l_data limit p_array_size;
        forall i in 1..l_data.count insert into t1 values l_data(i);
        exit when c%notfound;
      end loop;
      commit;
      close c;
    end usebatch;
    /

    执行上述存储过程

    SQL> exec nobatch;  
    Elapsed: 00:00:32.92

    SQL> exec usebatch(50);
    Elapsed: 00:00:00.77

    SQL> exec usebatch(100);
    Elapsed: 00:00:00.47

    SQL> exec usebatch(1000);
    Elapsed: 00:00:00.19

    SQL> exec usebatch(100000);
    Elapsed: 00:00:00.26

    存储过程批量执行效率也远远高于单条执行。查看usebatch(50)执行时的审计日志,sql_bind也只记录了批量执行的最后一个参数,即50的倍数。与使用executeBatch方法在记录内容方面相同。因此可以推断,JDBC的executeBatch和存储过程的批量执行都采用了相同的方法

    存储过程的这个关键点就是forall。查阅相关文档。

    The FORALL statement runs one DML statement multiple times, with different values in the VALUES and WHERE clauses.
    The different values come from existing, populated collections or host arrays. The FORALL statement is usually much faster than an equivalent FOR LOOP statement.
    The FORALL syntax allows us to bind the contents of a collection to a single DML statement, allowing the DML to be run for each row in the collection without requiring a context switch each time.

    翻译过来就是forall很快,原因就是不需要每次执行的时候等待参数。

    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!

    Déclaration
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer
    Comment le JVM gère-t-il les différences dans les API du système d'exploitation?Comment le JVM gère-t-il les différences dans les API du système d'exploitation?Apr 27, 2025 am 12:18 AM

    JVM gère les différences d'API du système d'exploitation via JavanativeInterface (JNI) et Java Standard Library: 1. JNI permet au code Java d'appeler le code local et d'interagir directement avec l'API du système d'exploitation. 2. La bibliothèque Java Standard fournit une API unifiée, qui est mappée en interne sur différentes API du système d'exploitation pour s'assurer que le code se déroule sur les plates-formes.

    Comment la modularité est-elle introduite dans Java 9 Impact Platform Independence?Comment la modularité est-elle introduite dans Java 9 Impact Platform Independence?Apr 27, 2025 am 12:15 AM

    ModularityDoesNotDirectlyAffectedJava'splatformIndependence.java'splatformIndependensemAINENENEYBYTHEJVM, ButModularityInfluencesPlicationsStructureAndManagement, indirectly ImpactingPlatFatFindependence.1)

    Qu'est-ce que ByteCode et comment cela se rapporte-t-il à l'indépendance de la plate-forme de Java?Qu'est-ce que ByteCode et comment cela se rapporte-t-il à l'indépendance de la plate-forme de Java?Apr 27, 2025 am 12:06 AM

    Bytecodeinjavaisheintermediaterepresentation the-steplatefortiveindependence.1) javacodeiscompilentocodedestoredin.classfiles.2) thejvMinterpretsorcompiltesthisbytecodeintomachinecotetruntime, permettant à la nom de codécodèdetorunonanydevicewithajvm, ainsi en nomycodetorunonananydevicewithajvm, ainsi.

    Pourquoi Java est-il considéré comme un langage indépendant de la plate-forme?Pourquoi Java est-il considéré comme un langage indépendant de la plate-forme?Apr 27, 2025 am 12:03 AM

    JavaachievesPlatformIndependencethroughthejavavirtualmachine (jvm), quixecutesbytecodeonanydevicewithajvm.1) javacodeiscompilentocode.2) thejvMinterpretsAndexExectestySByteintomachine-spécificestructions, permettre la réduction de la réduction de la masse

    Comment les interfaces graphiques des utilisateurs (GUIS) peuvent-elles présenter des défis pour l'indépendance de la plate-forme en Java?Comment les interfaces graphiques des utilisateurs (GUIS) peuvent-elles présenter des défis pour l'indépendance de la plate-forme en Java?Apr 27, 2025 am 12:02 AM

    L'indépendance de la plate-forme dans le développement de Javagui est confrontée à des défis, mais peut être traitée en utilisant Swing, Javafx, l'apparence unificatrice, l'optimisation des performances, les bibliothèques tierces et les tests multiplateformes. Le développement de Javagui repose sur AWT et Swing, qui vise à fournir une cohérence multiplateforme, mais l'effet réel varie du système d'exploitation au système d'exploitation. Les solutions comprennent: 1) l'utilisation de Swing et Javafx comme cases d'outils GUI; 2) Unifier l'apparence via uimanager.setLookAndFeel (); 3) Optimiser les performances en fonction des différentes plates-formes; 4) en utilisant des bibliothèques tierces telles que l'apachepivot ou le SWT; 5) effectuer des tests multiplateformes pour assurer la cohérence.

    Quels aspects du développement de Java dépendent de la plate-forme?Quels aspects du développement de Java dépendent de la plate-forme?Apr 26, 2025 am 12:19 AM

    JavadevelopmentSnotentivelyPlatform-indépendant de la duetoseveralfactors.1) jvmvariationSAffecctPerformanceAndbehavioracrossdifferentos.2) nativelibrarysviajniintroduceplatform-specificiss.3) goypathesystempropertiesdifferbetweenweenplateforms.4) goypathesmepropertiesdifferbetweenweenplateforms.4) guiaplicapropertiesdifferbetweenweenplateforms.4) guiaplicapropertiesdifferbetweenweenplateforms.4) guiaplicaaPropertiesdifferbetweenweenplateforms.4) GuiaplicaAplicaAplisses.

    Existe-t-il des différences de performances lors de l'exécution du code Java sur différentes plates-formes? Pourquoi?Existe-t-il des différences de performances lors de l'exécution du code Java sur différentes plates-formes? Pourquoi?Apr 26, 2025 am 12:15 AM

    Java Code aura des différences de performances lors de l'exécution sur différentes plates-formes. 1) Les stratégies de mise en œuvre et d'optimisation de JVM sont différentes, comme OracleJDK et OpenJDK. 2) Les caractéristiques du système d'exploitation, telles que la gestion de la mémoire et la planification des threads, affecteront également les performances. 3) Les performances peuvent être améliorées en sélectionnant le JVM approprié, en ajustant les paramètres JVM et l'optimisation du code.

    Quelles sont les limites de l'indépendance de la plate-forme de Java?Quelles sont les limites de l'indépendance de la plate-forme de Java?Apr 26, 2025 am 12:10 AM

    Java'splatformindependensencehaslimitations incluant la performance de la tête, les versions de verso, les défis avec l'intégration de la plate-forme spécifique et lajvminstallation / maintenance.

    See all articles

    Outils d'IA chauds

    Undresser.AI Undress

    Undresser.AI Undress

    Application basée sur l'IA pour créer des photos de nu réalistes

    AI Clothes Remover

    AI Clothes Remover

    Outil d'IA en ligne pour supprimer les vêtements des photos.

    Undress AI Tool

    Undress AI Tool

    Images de déshabillage gratuites

    Clothoff.io

    Clothoff.io

    Dissolvant de vêtements AI

    Video Face Swap

    Video Face Swap

    Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

    Outils chauds

    VSCode Windows 64 bits Télécharger

    VSCode Windows 64 bits Télécharger

    Un éditeur IDE gratuit et puissant lancé par Microsoft

    SublimeText3 Linux nouvelle version

    SublimeText3 Linux nouvelle version

    Dernière version de SublimeText3 Linux

    Bloc-notes++7.3.1

    Bloc-notes++7.3.1

    Éditeur de code facile à utiliser et gratuit

    SublimeText3 version chinoise

    SublimeText3 version chinoise

    Version chinoise, très simple à utiliser

    mPDF

    mPDF

    mPDF est une bibliothèque PHP qui peut générer des fichiers PDF à partir de HTML encodé en UTF-8. L'auteur original, Ian Back, a écrit mPDF pour générer des fichiers PDF « à la volée » depuis son site Web et gérer différentes langues. Il est plus lent et produit des fichiers plus volumineux lors de l'utilisation de polices Unicode que les scripts originaux comme HTML2FPDF, mais prend en charge les styles CSS, etc. et présente de nombreuses améliorations. Prend en charge presque toutes les langues, y compris RTL (arabe et hébreu) ​​et CJK (chinois, japonais et coréen). Prend en charge les éléments imbriqués au niveau du bloc (tels que P, DIV),