Java: Fügen Sie mit PreparedStatement mehrere Zeilen in MySQL ein

Lesezeit: 8 Minuten

Java Fugen Sie mit PreparedStatement mehrere Zeilen in MySQL ein
Tom Marthenal

Ich möchte mit Java mehrere Zeilen gleichzeitig in eine MySQL-Tabelle einfügen. Die Anzahl der Zeilen ist dynamisch. Früher habe ich das gemacht…

for (String element : array) {
    myStatement.setString(1, element[0]);
    myStatement.setString(2, element[1]);

    myStatement.executeUpdate();
}

Ich möchte dies optimieren, um die von MySQL unterstützte Syntax zu verwenden:

INSERT INTO table (col1, col2) VALUES ('val1', 'val2'), ('val1', 'val2')[, ...]

aber mit einem PreparedStatement Ich kenne keine Möglichkeit, dies zu tun, da ich vorher nicht weiß, wie viele Elemente array wird beinhalten. Wenn es mit a nicht möglich ist PreparedStatementwie kann ich es sonst tun (und trotzdem die Werte im Array maskieren)?

Java Fugen Sie mit PreparedStatement mehrere Zeilen in MySQL ein
BalusC

Sie können einen Stapel erstellen, indem Sie PreparedStatement#addBatch() und führen Sie es durch PreparedStatement#executeBatch().

Hier ist ein Kickoff-Beispiel:

public void save(List<Entity> entities) throws SQLException {
    try (
        Connection connection = database.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL_INSERT);
    ) {
        int i = 0;

        for (Entity entity : entities) {
            statement.setString(1, entity.getSomeProperty());
            // ...

            statement.addBatch();
            i++;

            if (i % 1000 == 0 || i == entities.size()) {
                statement.executeBatch(); // Execute every 1000 items.
            }
        }
    }
}

Es wird alle 1000 Elemente ausgeführt, da einige JDBC-Treiber und/oder DBs möglicherweise eine Begrenzung der Stapellänge haben.

Siehe auch:

  • Ihre Beilagen gehen schneller, wenn Sie sie in Transaktionen einfügen … dh mit umwickeln connection.setAutoCommit(false); und connection.commit(); download.oracle.com/javase/tutorial/jdbc/basics/…

    – Josua Martell

    4. Dezember 2010 um 20:39 Uhr


  • Sieht so aus, als könnten Sie einen leeren Stapel ausführen, wenn 999 Elemente vorhanden sind.

    – Djechlin

    7. März 2013 um 21:31 Uhr

  • @electricalbah es wird normal ausgeführt, weil i == entities.size()

    – Yohanim

    31. März 2017 um 6:43 Uhr


  • Hier ist eine weitere gute Ressource zum Zusammenstellen von Batch-Jobs mit vorbereiteten Anweisungen. viralpatel.net/blogs/batch-insert-in-java-jdbc

    – Danny Bullis

    3. Mai 2018 um 19:54 Uhr

  • @AndréPaulo: Nur ein beliebiges SQL INSERT, das für eine vorbereitete Anweisung geeignet ist. Unter den JDBC-Tutorial-Links finden Sie grundlegende Beispiele. Das hat nichts mit der konkreten Fragestellung zu tun.

    – BalusC

    4. Juni 2018 um 10:13 Uhr


Java Fugen Sie mit PreparedStatement mehrere Zeilen in MySQL ein
MichalSv

Wenn der MySQL-Treiber verwendet wird, müssen Sie die Verbindungsparameter festlegen rewriteBatchedStatements zu wahr ( jdbc:mysql://localhost:3306/TestDB?**rewriteBatchedStatements=true**).

Mit diesem Parameter wird die Anweisung auf Masseneinfügung umgeschrieben, wenn die Tabelle nur einmal gesperrt ist und Indizes nur einmal aktualisiert werden. Es geht also viel schneller.

Ohne diesen Parameter ist der einzige Vorteil ein sauberer Quellcode.

  • Dies ist ein Kommentar zur Leistung für die Konstruktion: statement.addBatch (); if ((i + 1) % 1000 == 0) { statement.executeBatch(); // Alle 1000 Elemente ausführen. }

    – MichalSv

    29. Mai 2014 um 16:27 Uhr


  • Anscheinend hat der MySQL-Treiber einen Fehler bugs.mysql.com/bug.php?id=71528 Dies verursacht auch Probleme für ORM-Frameworks wie Hibernate hibernate.atlassian.net/browse/HHH-9134

    – Shailendra

    31. Mai 2014 um 19:42 Uhr


  • Jawohl. Das ist jetzt auch richtig. Zumindest für 5.1.45 MySQL-Connector-Version.

    – v.ladynev

    27. Februar 2018 um 22:37 Uhr

  • mysql-connector-java 8.0.14 Gerade überprüft, ob 8.0.14 korrekt ist. Ohne hinzuzufügen rewriteBatchedStatements=true es gibt keinen leistungsgewinn.

    – Vincent Mathew

    18. Mai 2019 um 3:00 Uhr

1645978630 862 Java Fugen Sie mit PreparedStatement mehrere Zeilen in MySQL ein
Ali Shakiba

Wenn Sie Ihre SQL-Anweisung dynamisch erstellen können, können Sie die folgende Problemumgehung durchführen:

String myArray[][] = { { "1-1", "1-2" }, { "2-1", "2-2" }, { "3-1", "3-2" } };

StringBuffer mySql = new StringBuffer("insert into MyTable (col1, col2) values (?, ?)");

for (int i = 0; i < myArray.length - 1; i++) {
    mySql.append(", (?, ?)");
}

myStatement = myConnection.prepareStatement(mySql.toString());

for (int i = 0; i < myArray.length; i++) {
    myStatement.setString(i, myArray[i][1]);
    myStatement.setString(i, myArray[i][2]);
}
myStatement.executeUpdate();

  • Ich glaube, die akzeptierte Antwort ist viel besser !! Ich wusste nichts über Batch-Updates und als ich anfing, diese Antwort zu schreiben, wurde diese Antwort noch nicht gesendet !!! 🙂

    – Ali Shakiba

    4. Dezember 2010 um 23:20 Uhr

  • Dieser Ansatz ist viel schneller als der akzeptierte. Ich teste es, finde aber nicht warum. @JohnS weißt du warum?

    – julian0zzx

    21. November 2012 um 10:27 Uhr


  • @julian0zzx nein, aber vielleicht, weil es als einzelnes SQL statt als mehrere ausgeführt wird. aber ich bin mir nicht sicher.

    – Ali Shakiba

    23. November 2012 um 18:36 Uhr

Falls Sie eine automatische Inkrementierung in der Tabelle haben und darauf zugreifen müssen, können Sie den folgenden Ansatz verwenden … Führen Sie vor der Verwendung einen Test durch, da getGeneratedKeys () in der Anweisung verwendet wird, da dies vom verwendeten Treiber abhängt. Der folgende Code wurde auf Maria DB 10.0.12 und Maria JDBC-Treiber 1.2 getestet

Denken Sie daran, dass eine Erhöhung der Stapelgröße die Leistung nur bis zu einem gewissen Grad verbessert … für mein Setup hat die Erhöhung der Stapelgröße über 500 tatsächlich die Leistung beeinträchtigt.

public Connection getConnection(boolean autoCommit) throws SQLException {
    Connection conn = dataSource.getConnection();
    conn.setAutoCommit(autoCommit);
    return conn;
}

private void testBatchInsert(int count, int maxBatchSize) {
    String querySql = "insert into batch_test(keyword) values(?)";
    try {
        Connection connection = getConnection(false);
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        boolean success = true;
        int[] executeResult = null;
        try {
            pstmt = connection.prepareStatement(querySql, Statement.RETURN_GENERATED_KEYS);
            for (int i = 0; i < count; i++) {
                pstmt.setString(1, UUID.randomUUID().toString());
                pstmt.addBatch();
                if ((i + 1) % maxBatchSize == 0 || (i + 1) == count) {
                    executeResult = pstmt.executeBatch();
                }
            }
            ResultSet ids = pstmt.getGeneratedKeys();
            for (int i = 0; i < executeResult.length; i++) {
                ids.next();
                if (executeResult[i] == 1) {
                    System.out.println("Execute Result: " + i + ", Update Count: " + executeResult[i] + ", id: "
                            + ids.getLong(1));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            success = false;
        } finally {
            if (rs != null) {
                rs.close();
            }
            if (pstmt != null) {
                pstmt.close();
            }
            if (connection != null) {
                if (success) {
                    connection.commit();
                } else {
                    connection.rollback();
                }
                connection.close();
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

1645978630 441 Java Fugen Sie mit PreparedStatement mehrere Zeilen in MySQL ein
Wein

@Ali Shakiba Ihr Code muss geändert werden. Fehlerteil:

for (int i = 0; i < myArray.length; i++) {
     myStatement.setString(i, myArray[i][1]);
     myStatement.setString(i, myArray[i][2]);
}

Aktualisierter Code:

String myArray[][] = {
    {"1-1", "1-2"},
    {"2-1", "2-2"},
    {"3-1", "3-2"}
};

StringBuffer mySql = new StringBuffer("insert into MyTable (col1, col2) values (?, ?)");

for (int i = 0; i < myArray.length - 1; i++) {
    mySql.append(", (?, ?)");
}

mysql.append(";"); //also add the terminator at the end of sql statement
myStatement = myConnection.prepareStatement(mySql.toString());

for (int i = 0; i < myArray.length; i++) {
    myStatement.setString((2 * i) + 1, myArray[i][1]);
    myStatement.setString((2 * i) + 2, myArray[i][2]);
}

myStatement.executeUpdate();

  • Dies ist ein viel schnellerer und besserer Ansatz in der gesamten Antwort. Dies sollte die akzeptierte Antwort sein

    – Shankar-Guru

    9. November 2017 um 8:25 Uhr

  • Wie in der akzeptierten Antwort erwähnt, haben einige JDBC-Treiber / Datenbanken Beschränkungen für die Anzahl der Zeilen, die Sie in eine INSERT-Anweisung aufnehmen können. Im Fall des obigen Beispiels, wenn myArray länger als dieses Limit ist, tritt eine Ausnahme auf. In meinem Fall habe ich ein Limit von 1.000 Zeilen, was die Notwendigkeit einer Stapelausführung hervorruft, da ich möglicherweise mehr als 1.000 Zeilen bei einem bestimmten Lauf aktualisieren könnte. Diese Art von Anweisung sollte theoretisch gut funktionieren, wenn Sie wissen, dass Sie weniger als das maximal zulässige einfügen. Etwas zu beachten.

    – Danny Bullis

    3. Mai 2018 um 19:44 Uhr


  • Zur Verdeutlichung erwähnt die obige Antwort JDBC-Treiber/Datenbankbeschränkungen für die Stapellänge, aber es kann auch Beschränkungen für die Anzahl der Zeilen geben, die in einer Einfügeanweisung enthalten sind, wie ich in meinem Fall gesehen habe.

    – Danny Bullis

    3. Mai 2018 um 19:52 Uhr


Dies kann hilfreich sein, wenn Sie ein Array an übergeben PreparedStatement.

Speichern Sie die erforderlichen Werte in einem Array und übergeben Sie es an eine Funktion, um dieselben einzufügen.

String sql= "INSERT INTO table (col1,col2)  VALUES (?,?)";
String array[][] = new String [10][2];
for(int i=0;i<array.size();i++){
     //Assigning the values in individual rows.
     array[i][0] = "sampleData1";   
     array[i][1] = "sampleData2";
}
try{
     DBConnectionPrepared dbcp = new DBConnectionPrepared();            
     if(dbcp.putBatchData(sqlSaveAlias,array)==1){
        System.out.println("Success"); 
     }else{
        System.out.println("Failed");
     }
}catch(Exception e){
     e.printStackTrace();
}

putBatchData(sql,2D_Array)

public int[] putBatchData(String sql,String args[][]){
        int status[];
        try {
            PreparedStatement stmt=con.prepareStatement(sql);
            for(int i=0;i<args.length;i++){
                for(int j=0;j<args[i].length;j++){
                    stmt.setString(j+1, args[i][j]);
                }            
                stmt.addBatch();
                stmt.executeBatch();
                stmt.clearParameters();
            }
            status= stmt.executeBatch();             
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return status;
    }

  • Dies ist ein viel schnellerer und besserer Ansatz in der gesamten Antwort. Dies sollte die akzeptierte Antwort sein

    – Shankar-Guru

    9. November 2017 um 8:25 Uhr

  • Wie in der akzeptierten Antwort erwähnt, haben einige JDBC-Treiber / Datenbanken Beschränkungen für die Anzahl der Zeilen, die Sie in eine INSERT-Anweisung aufnehmen können. Im Fall des obigen Beispiels, wenn myArray länger als dieses Limit ist, tritt eine Ausnahme auf. In meinem Fall habe ich ein Limit von 1.000 Zeilen, was die Notwendigkeit einer Stapelausführung hervorruft, da ich möglicherweise mehr als 1.000 Zeilen bei einem bestimmten Lauf aktualisieren könnte. Diese Art von Anweisung sollte theoretisch gut funktionieren, wenn Sie wissen, dass Sie weniger als das maximal zulässige einfügen. Etwas zu beachten.

    – Danny Bullis

    3. Mai 2018 um 19:44 Uhr


  • Zur Verdeutlichung erwähnt die obige Antwort JDBC-Treiber/Datenbankbeschränkungen für die Stapellänge, aber es kann auch Beschränkungen für die Anzahl der Zeilen geben, die in einer Einfügeanweisung enthalten sind, wie ich in meinem Fall gesehen habe.

    – Danny Bullis

    3. Mai 2018 um 19:52 Uhr


1645978631 272 Java Fugen Sie mit PreparedStatement mehrere Zeilen in MySQL ein
ouflak

Es ist möglich, mehrere Updates einzureichen JDBC.

Wir können benutzen Statement, PreparedStatementund CallableStatement Objekte für die Stapelaktualisierung mit deaktiviertem Auto-Commit.

addBatch() und executeBatch() Funktionen sind mit allen Anweisungsobjekten verfügbar, um BatchUpdate zu haben.

Hier addBatch() -Methode fügt dem aktuellen Stapel eine Reihe von Anweisungen oder Parametern hinzu.

877910cookie-checkJava: Fügen Sie mit PreparedStatement mehrere Zeilen in MySQL ein

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy