这里的关键是:javax.servlet.jsp.jstl.sql.Result
这就是 JSTL 用作 SQL 查询的结果。如果你看一下界面,它有这个方法:
公共 java.util.SortedMap[] getRows()
c:forEach “知道” javax.servlet.jsp.jstl.sql.Result,因为 Result 不是 forEach 知道的任何其他东西(集合、数组、迭代器等)。
因此,所有这些都意味着 SQL 查询会将整个结果集吸入 RAM。
如果您因为不想将整个结果集加载到集合中而将查询移入 JSP,那么 SQL 标记似乎不会为您解决该问题。
实际上,您应该查找值列表模式。
但是,解决您的问题的“简单”解决方案是创建一个“了解”您的 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
}
}
}
这自然是未经测试的。但是由于 JSTL forEach 可以与 Iterator 一起使用,因此它是您可以真正传递给它的最简单的对象。这将阻止您将整个结果集加载到内存中。(顺便说一句,值得注意的是,ResultSets 行为与 Iterator 几乎但不完全不同。)