Chcę wstawić wiele wierszy jednocześnie do tabeli MySQL, używając języka Java. Liczba wierszy jest dynamiczna. W przeszłości robiłem ...
for (String element : array) {
myStatement.setString(1, element[0]);
myStatement.setString(2, element[1]);
myStatement.executeUpdate();
}
Chciałbym to zoptymalizować, aby używać składni obsługiwanej przez MySQL:
INSERT INTO table (col1, col2) VALUES ('val1', 'val2'), ('val1', 'val2')[, ...]
ale PreparedStatement
nie wiem, jak to zrobić, ponieważ nie wiem z góry, ile elementów array
będzie zawierać. Jeśli nie jest to możliwe z a PreparedStatement
, jak inaczej mogę to zrobić (i nadal uciec wartościom w tablicy)?
java
mysql
jdbc
prepared-statement
batch-insert
Tom Marthenal
źródło
źródło
connection.setAutoCommit(false);
iconnection.commit();
pobierz.oracle.com/javase/tutorial/jdbc/basics/ ...i == entities.size()
Gdy używany jest sterownik MySQL, musisz ustawić parametr połączenia
rewriteBatchedStatements
na true( jdbc:mysql://localhost:3306/TestDB?**rewriteBatchedStatements=true**)
.Z tym parametrem instrukcja jest przepisywana na wstawianie zbiorcze, gdy tabela jest blokowana tylko raz, a indeksy są aktualizowane tylko raz. Więc jest znacznie szybszy.
Bez tego parametru jedyną zaletą jest czystszy kod źródłowy.
źródło
5.1.45
wersji łącznika mysql.rewriteBatchedStatements=true
nie ma wzrostu wydajności.Jeśli możesz dynamicznie utworzyć instrukcję sql, możesz zastosować następujące obejście:
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();
źródło
W przypadku, gdy w tabeli znajduje się autoinkrementacja i potrzebujesz do niej dostępu ... możesz użyć następującego podejścia ... Przed użyciem wykonaj test, ponieważ getGeneratedKeys () w instrukcji, ponieważ zależy to od używanego sterownika. Poniższy kod jest testowany na Maria DB 10.0.12 i Maria JDBC sterownik 1.2
Pamiętaj, że zwiększenie rozmiaru partii poprawia wydajność tylko do pewnego stopnia ... w mojej konfiguracji zwiększenie rozmiaru partii powyżej 500 w rzeczywistości obniżyło wydajność.
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(); } }
źródło
@Ali Shakiba Twój kod wymaga modyfikacji. Część błędu:
for (int i = 0; i < myArray.length; i++) { myStatement.setString(i, myArray[i][1]); myStatement.setString(i, myArray[i][2]); }
Zaktualizowany kod:
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();
źródło
myArray
ma długość większą niż ten limit, trafisz na wyjątek. W moim przypadku mam limit 1000 wierszy, który wymusza wykonanie partii, ponieważ potencjalnie mogę aktualizować więcej niż 1000 wierszy w dowolnym przebiegu. Ten typ instrukcji powinien teoretycznie działać dobrze, jeśli wiesz, że wstawiasz mniej niż dozwolone maksimum. Coś, o czym warto pamiętać.możemy przesyłać wiele aktualizacji razem w JDBC, aby przesyłać aktualizacje zbiorcze.
możemy użyć obiektów Statement, PreparedStatement i CallableStatement do aktualizacji bacth z wyłączonym autocommit
Funkcje addBatch () i executeBatch () są dostępne we wszystkich obiektach instrukcji, aby mieć funkcję BatchUpdate
tutaj metoda addBatch () dodaje zestaw instrukcji lub parametrów do bieżącej partii.
źródło