jstl的sql标签如何工作?

我正在使用以下代码从我的jsp查询数据库,但我想知道更多关于幕后发生的事情。

这是我的两个主要问题。

标签是直接访问ResultSet,还是查询结果存储在内存中的数据结构中?

什么时候连接关闭?

   ${row.data } ${row.more_data }  

注意:我一直反对在jsp中运行查询,但我的结果集太大,无法在我的动作和我的jsp之间存储在内存中。 使用此标记库看起来是最简单的解决方案。

基于org.apache.taglibs.standard.tag.common.sql.QueryTagSupport的源的观察

taglib遍历ResultSet并将所有数据放入数组,映射和列表中。 因此,在开始循环之前,所有内容都会加载到内存中。

遇到查询开始标记时,将打开连接(doStartTag方法)。 遇到查询结束标记时检索结果(doEndTag方法)。 连接在doFinally方法中关闭。

简而言之,这绝对是可怕的。

这里的关键是:javax.servlet.jsp.jstl.sql.Result

这就是JSTL用作SQL查询的结果。 如果你看一下界面,它有这个方法:

public java.util.SortedMap [] getRows()

c:forEach“知道”javax.servlet.jsp.jstl.sql.Result,因为Result不是forEach知道的任何其他内容(集合,数组,迭代器等)。

因此,所有这些都意味着SQL查询会将整个结果集吸入RAM中。

如果您将查询移动到JSP中,因为您不想将整个结果集加载到集合中,那么它看起来不像SQL标记将为您解决该问题。

实际上你应该查找价值表模式。

但是,对您的问题的“简单”解决方案是创建一个“了解”您的ResultSet的自定义迭代器。 这个包装结果集并在遇到exception或结果运行的过程中关闭所有内容(就像在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的ResultSet行为。)