5.4. Large Result Sets

When using a JDBC driver that supports version 2.0 or higher of the JDBC specification, and that supports ResultSets of type TYPE_SCROLL_INSENSITIVE, collections returned from Query.execute methods will load rows from the database only when they are needed. This on-demand loading is also applied to javax.jdo.Extents.

The on-demand instantiation of elements of the ResultSet allows efficient handling of potentially very large result sets. Kodo JDO further conserves memory by using soft references to hold objects as they are instantiated during iteration. If the JVM begins to run low on memory, these objects will be garbage collected. Thus even query results or extents containing millions of objects can be fully iterated.

If an on-demand collection is ever completely instantiated, its soft references will be converted to hard references, and any database resources it is using will be freed. It becomes a standard collection of objects.

To facilitate users who require random access to query results, Kodo JDO always returns an implementation of java.util.List from calls to Query.execute. Remember, though, that other JDO implementations might choose to only implement the java.util.Collection interface in their query result objects. Also, note that unless ordering is specified in your query, there is no guarantee that multiple executions of the same query will return their results in the same order.

Example 5.3. Using Random Access Query Results in a Portable Fashion

// get start and end indexes of results to display from web request
int startIndex = Integer.parseInt (jspRequest.getParameter ("start"));
int endIndex = Integer.parseInt (jspRequest.getParameter ("end"));

Extent extent = pm.getExtent (Product.class, true);
Query query = pm.newQuery (extent, "productName == \"Stereo\"");

// we want to ensure that we always order the results in the same way
query.setOrdering ("productCode ascending");

Collection results = (Collection) query.execute ();
List resultList;
if (results instanceof List)
    resultList = (List) results;
else
    // portable, but it will wind up instantiating all elements in
    // collection, which might be a huge number of objects
    resultList = new ArrayList (results);

// print info about each product in list range from "start" to "end"
for (int i = startIndex; i <= endIndex && i < resultList.size (); i++)
    out.print ("Stereo #" + i + ": "
        + ((Product) resultList.get (i)).getDescription ());