[java] Как работает тег sql jstl?


Answers

Главное здесь: javax.servlet.jsp.jstl.sql.Result

Это то, что использует JSTL в результате SQL-запроса. Если вы посмотрите на интерфейс, у него есть этот метод:

public java.util.SortedMap [] getRows ()

c: forEach «знает» о javax.servlet.jsp.jstl.sql.Result, поскольку Result не является чем-то другим, о котором знает каждый (коллекции, массивы, итераторы и т. д.).

Таким образом, все это означает, что SQL-запрос будет всасывать весь набор результатов в ОЗУ.

Если вы перевели свой запрос в JSP, потому что не хотите загружать весь набор результатов в коллекцию, то это не похоже на то, что тег SQL решит эту проблему для вас.

По правде говоря, вы должны искать шаблон списка значений.

Но «простым» решением вашей проблемы было бы создание пользовательского Iterator, который «знает» о вашем ResultSet. Этот обертывает результирующий набор и закрывает все, если он встречает исключение или результат заканчивается (например, в forEach). Вид вещи особого назначения.

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

}

Это, естественно, непроверено. Но поскольку JSTLs forEach может работать с Iterator, это самый простой объект, который вы действительно могли бы передать ему. Это предотвратит загрузку всего набора результатов в память. (Как интересно в сторону, примечательно, насколько почти, но не совсем, совершенно не похоже на Iterator поведение ResultSets.)

Question

Я использую следующий код для запроса базы данных из моего jsp, но я хотел бы узнать больше о том, что происходит за кулисами.

Это мои два основных вопроса.

Является ли тег напрямую доступ к ResultSet или же результат запроса хранится в структуре данных в памяти?

Когда соединение закрыто?

<%@ 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>

Примечание. Я всегда выступал против запуска запросов в jsp, но мой результирующий набор слишком велик для хранения в памяти между моим действием и моим jsp. Использование этой библиотеки тегов выглядит как самое простое решение.




Links