2010-01-19 17 views
6

Estoy tratando de revisar cada fila de una tabla en MySQL usando Spring y una JdbcTemplate. Si no me equivoco esto debería ser tan simple como:Cómo administrar un gran conjunto de datos usando Spring MySQL y RowCallbackHandler

JdbcTemplate template = new JdbcTemplate(datasource); 
template.setFetchSize(1); 
// template.setFetchSize(Integer.MIN_VALUE) does not work either    
template.query("SELECT * FROM cdr", new RowCallbackHandler() { 
    public void processRow(ResultSet rs) throws SQLException { 
    System.out.println(rs.getString("src")); 
    } 
}); 

consigo un OutOfMemoryError porque está tratando de leer todo el asunto. ¿Algunas ideas?

+0

Hey, cuidado para cambiar la respuesta aceptada. Su pregunta fue sobre Spring y la respuesta de @ scompt.com es más apropiada. Muchas gracias. – Gray

Respuesta

9

El Statement#setFetchSize()javadoc ya se afirma:

da al conductor JDBC un toque en cuanto al número de filas que se debe recuperar de la base de datos

El controlador es realmente libre de aplicar o ignorar la sugerencia. Algunos controladores lo ignoran, algunos controladores lo aplican directamente, algunos controladores necesitan más parámetros. El controlador JDBC de MySQL cae en la última categoría. Si marca la MySQL JDBC driver documentation, verá la siguiente información (desplazarse hacia abajo hasta aproximadamente 2/3 de cabecera conjunto de resultados):

Para activar esta funcionalidad, es necesario crear una instancia Declaración de la siguiente forma:

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY); 
stmt.setFetchSize(Integer.MIN_VALUE); 

Por favor, lea toda la sección del documento, que describe las advertencias de este enfoque también.

Para que funcione en Spring, sin embargo, necesitará ampliar/anular JdbcTemplate con una implementación personalizada. Como no hago primavera, no puedo entrar en detalles sobre esto, pero ahora al menos sabes dónde buscar.

Buena suerte.

+2

He agregado una solución basada en Spring aquí: http://stackoverflow.com/questions/2095490/how-to-manage-a-large-dataset-using-spring- mysql-and-rowcallbackhandler/2834590 # 2834590 –

0

Si sospecha que está recibiendo el error OutOfMemory debido a la lectura de toda la tabla, ¿por qué no intenta dividir su consulta? Use filtros, etc. cláusula de límite

+1

Eso haría que la lógica del proceso sea mucho más compleja. Ahora estoy probando una forma de hacer realmente la transmisión a través de Spring JdbcTeamplate. Le avisaré si funciona ... – rmarimon

18

Aquí hay una solución Spring basada en el answer proporcionada por BalusC.

class StreamingStatementCreator implements PreparedStatementCreator { 
    private final String sql; 

    public StreamingStatementCreator(String sql) { 
     this.sql = sql; 
    } 

    @Override 
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { 
     final PreparedStatement statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); 
     statement.setFetchSize(Integer.MIN_VALUE); 
     return statement; 
    } 
} 

En algún lugar de su código:

DataSource dataSource = ...; 
RowCallbackHandler rowHandler = ...; 
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 
jdbcTemplate.query(new StreamingStatementCreator("SELECT * FROM huge_table"), rowHandler); 
+1

, vale la pena señalar que debe asegurarse de que la propiedad useServerPrepStmts en su cadena de conexión está configurada correctamente, es decir, si por casualidad este conjunto a falso ^^ no funcionará y guardará el resultado completo establecer –

+0

Vale la pena señalar que con Spring 3 el setFetchSize de JdbcTemplate ignora los límites menores que 1 y por lo tanto, usted tiene que anular una característica muy básica. Yuck. –

+0

@AndrewGilmartin Después de 4.3, debería funcionar- Nota: A partir del 4.3, los valores negativos que no sean -1 pasarán al controlador, ya que p. MySQL admite un comportamiento especial para Integer.MIN_VALUE. – Hlex

Cuestiones relacionadas