Inserire nuovi record in una tabella è un'operazione semplicissima, ma se si ha la necessità di inserire centinaia di migliaia di record contemporaneamente (ad esempio si stanno importando molti dati da un file CSV) l'operazione può diventare molto -troppo- lenta.
Analizziamo una possibile una soluzione, in Java, utilizzando le API JDBC.
Vogliamo una soluzione performante e al sicuro da SQL Injection, per cui utilizzeremo questo approccio:
apriamo la connessione verso il database
disabilitiamo l'autocommit
per ogni gruppo di N elementi da inserire (es 1.000)
utilizzando un PreparedStatament, facciamo delle batch insert
eseguiamo un commit
chiudiamo la connessione
Una possibile implementazione di questo approccio è la seguente:
// l'oggetto ds è il datasource
DataSource ds = ...
// Questi sono i dati da inserire sul database
// facciamo finta che siano in una lista
List rows = ...
// inseriamo le righe 1000 per volta
final int batchSize = 1000;
// query di inserimento singolo record
String query = "INSERT INTO tabella(campo1, campo2) VALUES(?, ?)";
// Procediamo con le insert via batch/commit
try(Connection connection=ds.getConnection(); PreparedStatement ps = connection.prepareStatement(query)) {
boolean previousAutocommit = connection.getAutoCommit();
// l'autocommit viene disabilitato
connection.setAutoCommit(false);
int count = 0;
for(Oggetto r: rows) {
ps.setObject(1, r.getCampo1());
ps.setObject(2, r.getCampo2());
ps.addBatch();
// al raggiungimento dei 1000 record facciamo il commit
if(++count>=batchSize) {
count = 0;
ps.executeBatch();
connection.commit();
}
}
// commit dell'eventuale ultimo blocco
// con meno di 1000 record rimanente
ps.executeBatch();
connection.commit();
}
finally {
connection.setAutoCommit(previousAutocommit);
}
Nel caso in cui il database utilizzato sia MySQL, avrete un incremento delle perfomance notevole aggiungendo questi due parametri di connessione:
rewriteBatchedStatements=true
useCompression=true