Pregunta

Estoy usando el siguiente código para consultar una base de datos desde mi jsp, pero me gustaría saber más sobre lo que sucede detrás de escena.

Estas son mis dos preguntas principales.

¿La etiqueta accede directamente al ResultSet o el resultado de la consulta se almacena en una estructura de datos en la memoria?

¿Cuándo se cierra la conexión?

<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>

<sql:query var="query" dataSource="${ds}" sql="${listQuery}"></sql:query>
<c:forEach var="row" items="${query.rows}" begin="0">
    ${row.data }
    ${row.more_data }
</c:forEach>

Nota:Siempre he estado en contra de ejecutar consultas en jsp, pero mi conjunto de resultados es demasiado grande para almacenarlo en la memoria entre mi acción y mi jsp.Usar esta biblioteca de etiquetas parece la solución más sencilla.

¿Fue útil?

Solución

Observaciones basadas en la fuente de org.apache.taglibs.standard.tag.common.sql.QueryTagSupport

Taglib atraviesa ResultSet y coloca todos los datos en matrices, mapas y listas.Entonces, todo se carga en la memoria incluso antes de comenzar a realizar el bucle.

La conexión se abre cuando se encuentra la etiqueta de inicio de la consulta (método doStartTag).Los resultados se recuperan cuando se encuentra la etiqueta final de la consulta (método doEndTag).La conexión se cierra en el método doFinally.

En pocas palabras, es absolutamente horrible.

Otros consejos

La clave aquí es esta:javax.servlet.jsp.jstl.sql.Resultado

Eso es lo que utiliza JSTL como resultado de una consulta SQL.Si miras la interfaz, tiene este método:

público java.util.SortedMap[] getRows()

c:forEach "sabe" acerca de javax.servlet.jsp.jstl.sql.Result, ya que Result no es nada más que forEach conozca (colecciones, matrices, iteradores, etc.).

Entonces, todo eso implica que la consulta SQL absorberá todo el conjunto de resultados en la RAM.

Si movió su consulta al JSP porque no quería cargar el conjunto de resultados completo en una colección, entonces no parece que la etiqueta SQL resuelva ese problema por usted.

En verdad, deberías buscar Patrón de lista de valores.

Pero una solución "simple" a su problema sería crear un iterador personalizado que "conozca" su conjunto de resultados.Éste envuelve un conjunto de resultados y cierra todo si encuentra una excepción o si el resultado sigue su curso (como lo haría en forEach).Algo así como algo con un propósito especial.

public class ResultSetIterator implements Iterator {

Connection con;
Statement s;
ResultSet rs;
Object curObject;
boolean closed;

public ResultSetIterator(Connection con, Statement s, ResultSet rs) {
    this.con = con;
    this.s = s;
    this.rs = rs;
    closed = false;
}

public boolean hasNext() {
    advance();
    return curObject != null;
}

public Object next() {
    advance();
    if (curObject == null) {
        throw new NoSuchElementException();
    } else {
        Object result = curObject;
        curObject = null;
        return result;
    }
}

public void remove() {
    throw new UnsupportedOperationException("Not supported yet.");
}

private void advance() {
    if (closed) {
        curObject = null;
        return;
    }
    if (curObject == null) {
        try {
            if (rs.next()) {
                curObject = bindObject(rs);
            }
        } catch (SQLException ex) {
            shutDown();
            throw new RuntimeException(ex);
        }
    }
    if (curObject == null) {
        // Still no object, must be at the end of the result set
        shutDown();
    }
}

protected Object bindObject(ResultSet rs) throws SQLException {
    // Bind result set row to an object, replace or override this method
    String name = rs.getString(1);
    return name;
}

public void shutDown() {
    closed = true;
    try {
        rs.close();
    } catch (SQLException ex) {
        // Ignored
    }
    try {
        s.close();
    } catch (SQLException ex) {
        // Ignored
    }
    try {
        con.close();
    } catch (SQLException ex) {
        // Ignored
    }
}

}

Esto, naturalmente, no ha sido probado.Pero dado que los JSTL para cada uno pueden funcionar con un iterador, es el objeto más simple que realmente se le puede pasar.Esto evitará que cargue todo el conjunto de resultados en la memoria.(Como comentario interesante, es notable cuán casi, pero no completamente, diferente es el comportamiento de Iterator a ResultSets).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top