Pergunta

Eu estou usando o seguinte código para consultar um banco de dados do meu jsp, mas eu gostaria de saber mais sobre o que está acontecendo nos bastidores.

Estas são as minhas duas perguntas principais.

Será que o acesso tag do ResultSet diretamente, ou é o resultado da consulta que está sendo armazenado em uma estrutura de dados na memória?

Quando é a conexão fechada?

<%@ 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: Sempre fui contra a execução de consultas no jsp, mas meu conjunto de resultados é muito grande para armazenar na memória entre minha ação e meu jsp. Usando isso parece biblioteca tag como a solução mais fácil.

Foi útil?

Solução

As observações baseadas na fonte para org.apache.taglibs.standard.tag.common.sql.QueryTagSupport

As travessias taglib através do ResultSet e coloca todos os dados em matrizes, mapas e listas. Então, tudo é carregado na memória antes mesmo de começar looping.

A conexão é aberta quando a marca de início da consulta for encontrado (método doStartTag). Os resultados são obtidos quando a tag end consulta for encontrado (método doEndTag). A conexão é fechada no método doFinally.

É poucas palavras, é absolutamente terrível.

Outras dicas

A coisa chave aqui é esta: javax.servlet.jsp.jstl.sql.Result

Isso é o que JSTL usos como o resultado de uma consulta SQL. Se você olhar para a interface, ele tem esse método:

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

c: forEach "sabe" sobre javax.servlet.jsp.jstl.sql.Result, já que resultado não é outra coisa que forEach sabe sobre (Coleções, arrays, iteradores, etc)

.

Então, tudo isso implica que a consulta SQL vai sugar todo o conjunto de resultados para a RAM.

Se você moveu sua consulta para o JSP, porque você não quer carregar todo o conjunto de resultados para uma coleção, então ele não se parece com a tag SQL vai resolver esse problema para você.

Na verdade você deve olhar para cima lista de valores padrão.

Mas uma solução "simples" para o problema seria a criação de um costume Iterator que "sabe" sobre o seu ResultSet. Este envolve um conjunto de resultados e fecha tudo se encontra uma exceção ou se o resultado segue seu curso (como seria em um foreach). Um tipo de coisa de propósito específico.

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
    }
}

}

Este é, naturalmente, não foi testado. Mas desde JSTLs forEach pode trabalhar com um Iterator, é o objeto mais simples que você pode realmente passar para ele. Isto irá impedi-lo de carregar todo o conjunto de resultados para a memória. (Como um aparte interessante, é notável como quase, mas não completamente, completamente diferente de Iterator um comportamento ResultSets é.)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top