📄 largeselect.java
字号:
package org.apache.torque.util;/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Turbine" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Turbine", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */import java.sql.Connection;import java.sql.SQLException;import java.util.Iterator;import java.util.List;import java.util.ArrayList;import java.util.Hashtable;import java.util.Set;import java.io.Serializable;import java.lang.reflect.Method;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.apache.torque.Torque;import org.apache.torque.TorqueException;import com.workingdogs.village.QueryDataSet;import com.workingdogs.village.DataSetException;/** * This class can be used to retrieve a large result set from a database query. * The query is started and then rows are returned a page at a time. The <code> * LargeSelect</code> is meant to be placed into the Session or User.Temp, so * that it can be used in response to several related requests. Note that in * order to use <code>LargeSelect</code> you need to be willing to accept the * fact that the result set may become inconsistent with the database if updates * are processed subsequent to the queries being executed. Specifying a memory * page limit of 1 will give you a consistent view of the records but the totals * may not be accurate and the performance will be terrible. In most cases * the potential for inconsistencies data should not cause any serious problems * and performance should be pretty good (but read on for further warnings). * * <p>The idea here is that the full query result would consume too much memory * and if displayed to a user the page would be too long to be useful. Rather * than loading the full result set into memory, a window of data (the memory * limit) is loaded and retrieved a page at a time. If a request occurs for * data that falls outside the currently loaded window of data then a new query * is executed to fetch the required data. Performance is optimized by * starting a thread to execute the database query and fetch the results. This * will perform best when paging forwards through the data, but a minor * optimization where the window is moved backwards by two rather than one page * is included for when a user pages past the beginning of the window. * * <p>As the query is performed in in steps, it is often the case that the total * number of records and pages of data is unknown. <code>LargeSelect</code> * provides various methods for indicating how many records and pages it is * currently aware of and for presenting this information to users. * * <p><code>LargeSelect</code> utilises the <code>Criteria</code> methods * <code>setOffset()</code> and <code>setLimit()</code> to limit the amount of * data retrieved from the database - these values are either passed through to * the DBMS when supported (efficient with the caveat below) or handled by * the Village API when it is not (not so efficient). At time of writing * <code>Criteria</code> will only pass the offset and limit through to MySQL * and PostgreSQL (with a few changes to <code>DBOracle</code> and <code> * BasePeer</code> Oracle support can be implemented by utilising the <code> * rownum</code> pseudo column). * * <p>As <code>LargeSelect</code> must re-execute the query each time the user * pages out of the window of loaded data, you should consider the impact of * non-index sort orderings and other criteria that will require the DBMS to * execute the entire query before filtering down to the offset and limit either * internally or via Village. * * <p>The memory limit defaults to 5 times the page size you specify, but * alternative constructors and the class method <code>setMemoryPageLimit() * </code> allow you to override this for a specific instance of * <code>LargeSelect</code> or future instances respectively. * * <p>Some of the constructors allow you to specify the name of the class to use * to build the returnd rows. This works by using reflection to find <code> * addSelectColumns(Criteria)</code> and <code>populateObjects(List)</code> * methods to add the necessary select columns to the criteria (only if it * doesn't already contain any) and to convert query results from Village * <code>Record</code> objects to a class defined within the builder class. * This allows you to use any of the Torque generated Peer classes, but also * makes it fairly simple to construct business object classes that can be used * for this purpose (simply copy and customise the <code>addSelectColumns() * </code>, <code>populateObjects()</code>, <code>row2Object()</code> and <code> * populateObject()</code> methods from an existing Peer class). * * <p>Typically you will create a <code>LargeSelect</code> using your <code> * Criteria</code> (perhaps created from the results of a search parameter * page), page size, memory page limit and return class name (for which you may * have defined a business object class before hand) and place this in user.Temp * thus: * * <pre> * data.getUser().setTemp("someName", largeSelect); * </pre> * * <p>In your template you will then use something along the lines of: * * <pre> * #set ($largeSelect = $data.User.getTemp("someName")) * #set ($searchop = $data.Parameters.getString("searchop")) * #if ($searchop.equals("prev")) * #set ($recs = $largeSelect.PreviousResults) * #else * #if ($searchop.equals("goto")) * #set ($recs * = $largeSelect.getPage($data.Parameters.getInt("page", 1))) * #else * #set ($recs = $largeSelect.NextResults) * #end * #end * </pre> * * <p>...to move through the records. <code>LargeSelect</code> implements a * number of convenience methods that make it easy to add all of the necessary * bells and whistles to your template. * * @author <a href="mailto:john.mcnally@clearink.com">John D. McNally</a> * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a> * @version $Id: LargeSelect.java,v 1.13 2003/08/25 16:33:23 henning Exp $ */public class LargeSelect implements Runnable, Serializable{ /** The number of records that a page consists of. */ private int pageSize; /** The maximum number of records to maintain in memory. */ private int memoryLimit; /** The record number of the first record in memory. */ private int blockBegin = 0; /** The record number of the last record in memory. */ private int blockEnd; /** How much of the memory block is currently occupied with result data. */ private volatile int currentlyFilledTo = -1; /** The SQL query that this <code>LargeSelect</code> represents. */ private String query; /** The database name to get from Torque. */ private String dbName; /** Used to retrieve query results from Village. */ private QueryDataSet qds = null; /** The memory store of records. */ private List results = null; /** The thread that executes the query. */ private Thread thread = null; /** * A flag used to kill the thread when the currently executing query is no * longer required. */ private volatile boolean killThread = false; /** A flag that indicates whether or not the query thread is running. */ private volatile boolean threadRunning = false; /** * An indication of whether or not the current query has completed * processing. */ private volatile boolean queryCompleted = false; /** * An indication of whether or not the totals (records and pages) are at * their final values. */ private boolean totalsFinalized = false; /** The cursor position in the result set. */ private int position; /** The total number of pages known to exist. */ private int totalPages = -1; /** The total number of records known to exist. */ private int totalRecords = 0; /** The number of the page that was last retrieved. */ private int currentPageNumber = 0; /** The criteria used for the query. */ private Criteria criteria = null; /** The last page of results that were returned. */ private List lastResults; /** * The class that is possibly used to construct the criteria and used * to transform the Village Records into the desired OM or business objects. */ private Class returnBuilderClass = null; /** * A reference to the method in the return builder class that will * convert the Village Records to the desired class. */ private Method populateObjectsMethod = null; /** * The default value (">") used to indicate that the total number of * records or pages is unknown. You can use <code>setMoreIndicator()</code> * to change this to whatever value you like (e.g. "more than"). */ public static final String DEFAULT_MORE_INDICATOR = ">"; private static String moreIndicator = DEFAULT_MORE_INDICATOR; /** * The default value for the maximum number of pages of data to be retained * in memory - you can provide your own default value using * <code>setMemoryPageLimit()</code>. */ public static final int DEFAULT_MEMORY_LIMIT_PAGES = 5; private static int memoryPageLimit = DEFAULT_MEMORY_LIMIT_PAGES; /** A place to store search parameters that relate to this query. */ private Hashtable params = null; /** Logging */ private static Log log = LogFactory.getLog(LargeSelect.class); /** * Creates a LargeSelect whose results are returned as a <code>List</code> * containing a maximum of <code>pageSize</code> Village <code>Record</code> * objects at a time, maintaining a maximum of * <code>LargeSelect.memoryPageLimit</code> pages of results in memory. * * @param criteria object used by BasePeer to build the query. In order to * allow this class to utilise database server implemented offsets and * limits (when available), the provided criteria must not have any limit or * offset defined. * @param pageSize number of rows to return in one block. * @throws IllegalArgumentException if <code>criteria</code> uses one or * both of offset and limit, or if <code>pageSize</code> is less than 1; */ public LargeSelect(Criteria criteria, int pageSize) throws IllegalArgumentException { this(criteria, pageSize, LargeSelect.memoryPageLimit); } /** * Creates a LargeSelect whose results are returned as a <code>List</code> * containing a maximum of <code>pageSize</code> Village <code>Record</code> * objects at a time, maintaining a maximum of <code>memoryPageLimit</code> * pages of results in memory. * * @param criteria object used by BasePeer to build the query. In order to * allow this class to utilise database server implemented offsets and * limits (when available), the provided criteria must not have any limit or * offset defined. * @param pageSize number of rows to return in one block. * @param memoryPageLimit maximum number of pages worth of rows to be held * in memory at one time. * @throws IllegalArgumentException if <code>criteria</code> uses one or * both of offset and limit, or if <code>pageSize</code> or * <code>memoryLimitPages</code> are less than 1; */ public LargeSelect(Criteria criteria, int pageSize, int memoryPageLimit) throws IllegalArgumentException { init(criteria, pageSize, memoryPageLimit); } /** * Creates a LargeSelect whose results are returned as a <code>List</code> * containing a maximum of <code>pageSize</code> objects of the type * defined within the class named <code>returnBuilderClassName</code> at a * time, maintaining a maximum of <code>LargeSelect.memoryPageLimit</code> * pages of results in memory. * * @param criteria object used by BasePeer to build the query. In order to * allow this class to utilise database server implemented offsets and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -