JDBC Lote Insertar OutOfMemoryError
batch-file large-data-volumes (2)
Se ha executeBatch
sin memoria porque contiene toda la transacción en la memoria y solo la envía a la base de datos cuando se executeBatch
.
Si no necesita que sea atómico y desea obtener un mejor rendimiento, puede conservar un contador y executeBatch
cada n cantidad de registros.
He escrito un método insert()
en el que estoy tratando de usar JDBC Batch para insertar medio millón de registros en una base de datos MySQL:
public void insert(int nameListId, String[] names) {
String sql = "INSERT INTO name_list_subscribers (name_list_id, name, date_added)"+
" VALUES (?, ?, NOW())";
Connection conn = null;
PreparedStatement ps = null;
try{
conn = getConnection();
ps = conn.prepareStatement(sql);
for(String s : names ){
ps.setInt(1, nameListId);
ps.setString(2, s);
ps.addBatch();
}
ps.executeBatch();
}catch(SQLException e){
throw new RuntimeException(e);
}finally{
closeDbResources(ps, null, conn);
}
}
Pero cada vez que intento ejecutar este método, aparece el siguiente error:
java.lang.OutOfMemoryError: Java heap space
com.mysql.jdbc.ServerPreparedStatement$BatchedBindValues.<init>(ServerPreparedStatement.java:72)
com.mysql.jdbc.ServerPreparedStatement.addBatch(ServerPreparedStatement.java:330)
org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:171)
Si reemplazo ps.addBatch()
con ps.executeUpdate()
y ps.executeBatch()
, funciona bien, aunque lleva algo de tiempo. Por favor, avíseme si sabe si usar Batch es apropiado en esta situación, y si lo es, ¿por qué da OurOfMemoryError
?
Gracias
addBatch
y executeBatch
dan el mecanismo para realizar inserciones por lotes, pero aún necesita hacer el algoritmo de procesamiento por lotes usted mismo.
Si simplemente apila cada instrucción en el mismo lote, como lo está haciendo, entonces se quedará sin memoria. Necesita ejecutar / borrar el lote cada n
registros. El valor de n
depende de usted, JDBC no puede tomar esa decisión por usted. Cuanto mayor sea el tamaño del lote, más rápido irán las cosas, pero es demasiado grande y se morirá de memoria y las cosas se ralentizarán o fallarán. Depende de cuánta memoria tienes.
Comience con un tamaño de lote de 1000, por ejemplo, y experimente con diferentes valores desde allí.
final int batchSize = 1000;
int count = 0;
for(String s : names ) {
ps.setInt(1, nameListId);
ps.setString(2, s);
ps.addBatch();
if (++count % batchSize == 0) {
ps.executeBatch();
ps.clearBatch(); //not sure if this is necessary
}
}
ps.executeBatch(); // flush the last few records.