Como é que jstl sql trabalho tag?
-
01-07-2019 - |
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.
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 é.)