📄 loader.java
字号:
//$Id: Loader.java 11398 2007-04-10 14:54:07Z steve.ebersole@jboss.com $package org.hibernate.loader;import java.io.Serializable;import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.hibernate.AssertionFailure;import org.hibernate.HibernateException;import org.hibernate.LockMode;import org.hibernate.QueryException;import org.hibernate.ScrollMode;import org.hibernate.ScrollableResults;import org.hibernate.StaleObjectStateException;import org.hibernate.WrongClassException;import org.hibernate.cache.FilterKey;import org.hibernate.cache.QueryCache;import org.hibernate.cache.QueryKey;import org.hibernate.collection.PersistentCollection;import org.hibernate.dialect.Dialect;import org.hibernate.engine.EntityKey;import org.hibernate.engine.EntityUniqueKey;import org.hibernate.engine.PersistenceContext;import org.hibernate.engine.QueryParameters;import org.hibernate.engine.RowSelection;import org.hibernate.engine.SessionFactoryImplementor;import org.hibernate.engine.SessionImplementor;import org.hibernate.engine.SubselectFetch;import org.hibernate.engine.TwoPhaseLoad;import org.hibernate.engine.TypedValue;import org.hibernate.event.EventSource;import org.hibernate.event.PostLoadEvent;import org.hibernate.event.PreLoadEvent;import org.hibernate.exception.JDBCExceptionHelper;import org.hibernate.hql.HolderInstantiator;import org.hibernate.impl.FetchingScrollableResultsImpl;import org.hibernate.impl.ScrollableResultsImpl;import org.hibernate.jdbc.ColumnNameCache;import org.hibernate.jdbc.ResultSetWrapper;import org.hibernate.persister.collection.CollectionPersister;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.persister.entity.Loadable;import org.hibernate.persister.entity.UniqueKeyLoadable;import org.hibernate.pretty.MessageHelper;import org.hibernate.proxy.HibernateProxy;import org.hibernate.transform.ResultTransformer;import org.hibernate.type.AssociationType;import org.hibernate.type.EntityType;import org.hibernate.type.Type;import org.hibernate.type.VersionType;import org.hibernate.util.StringHelper;/** * Abstract superclass of object loading (and querying) strategies. This class implements * useful common functionality that concrete loaders delegate to. It is not intended that this * functionality would be directly accessed by client code. (Hence, all methods of this class * are declared <tt>protected</tt> or <tt>private</tt>.) This class relies heavily upon the * <tt>Loadable</tt> interface, which is the contract between this class and * <tt>EntityPersister</tt>s that may be loaded by it.<br> * <br> * The present implementation is able to load any number of columns of entities and at most * one collection role per query. * * @author Gavin King * @see org.hibernate.persister.entity.Loadable */public abstract class Loader { private static final Logger log = LoggerFactory.getLogger( Loader.class ); private final SessionFactoryImplementor factory; private ColumnNameCache columnNameCache; public Loader(SessionFactoryImplementor factory) { this.factory = factory; } /** * The SQL query string to be called; implemented by all subclasses * * @return The sql command this loader should use to get its {@link ResultSet}. */ protected abstract String getSQLString(); /** * An array of persisters of entity classes contained in each row of results; * implemented by all subclasses * * @return The entity persisters. */ protected abstract Loadable[] getEntityPersisters(); /** * An array indicating whether the entities have eager property fetching * enabled. * * @return Eager property fetching indicators. */ protected boolean[] getEntityEagerPropertyFetches() { return null; } /** * An array of indexes of the entity that owns a one-to-one association * to the entity at the given index (-1 if there is no "owner"). The * indexes contained here are relative to the result of * {@link #getEntityPersisters}. * * @return The owner indicators (see discussion above). */ protected int[] getOwners() { return null; } /** * An array of the owner types corresponding to the {@link #getOwners()} * returns. Indices indicating no owner would be null here. * * @return The types for the owners. */ protected EntityType[] getOwnerAssociationTypes() { return null; } /** * An (optional) persister for a collection to be initialized; only * collection loaders return a non-null value */ protected CollectionPersister[] getCollectionPersisters() { return null; } /** * Get the index of the entity that owns the collection, or -1 * if there is no owner in the query results (ie. in the case of a * collection initializer) or no collection. */ protected int[] getCollectionOwners() { return null; } /** * What lock mode does this load entities with? * * @param lockModes a collection of lock modes specified dynamically via the Query interface */ protected abstract LockMode[] getLockModes(Map lockModes); /** * Append <tt>FOR UPDATE OF</tt> clause, if necessary. This * empty superclass implementation merely returns its first * argument. */ protected String applyLocks(String sql, Map lockModes, Dialect dialect) throws HibernateException { return sql; } /** * Does this query return objects that might be already cached * by the session, whose lock mode may need upgrading */ protected boolean upgradeLocks() { return false; } /** * Return false is this loader is a batch entity loader */ protected boolean isSingleRowLoader() { return false; } /** * Get the SQL table aliases of entities whose * associations are subselect-loadable, returning * null if this loader does not support subselect * loading */ protected String[] getAliases() { return null; } /** * Modify the SQL, adding lock hints and comments, if necessary */ protected String preprocessSQL(String sql, QueryParameters parameters, Dialect dialect) throws HibernateException { sql = applyLocks( sql, parameters.getLockModes(), dialect ); return getFactory().getSettings().isCommentsEnabled() ? prependComment( sql, parameters ) : sql; } private String prependComment(String sql, QueryParameters parameters) { String comment = parameters.getComment(); if ( comment == null ) { return sql; } else { return new StringBuffer( comment.length() + sql.length() + 5 ) .append( "/* " ) .append( comment ) .append( " */ " ) .append( sql ) .toString(); } } /** * Execute an SQL query and attempt to instantiate instances of the class mapped by the given * persister from each row of the <tt>ResultSet</tt>. If an object is supplied, will attempt to * initialize that object. If a collection is supplied, attempt to initialize that collection. */ private List doQueryAndInitializeNonLazyCollections(final SessionImplementor session, final QueryParameters queryParameters, final boolean returnProxies) throws HibernateException, SQLException { final PersistenceContext persistenceContext = session.getPersistenceContext(); persistenceContext.beforeLoad(); List result; try { result = doQuery( session, queryParameters, returnProxies ); } finally { persistenceContext.afterLoad(); } persistenceContext.initializeNonLazyCollections(); return result; } /** * Loads a single row from the result set. This is the processing used from the * ScrollableResults where no collection fetches were encountered. * * @param resultSet The result set from which to do the load. * @param session The session from which the request originated. * @param queryParameters The query parameters specified by the user. * @param returnProxies Should proxies be generated * @return The loaded "row". * @throws HibernateException */ public Object loadSingleRow( final ResultSet resultSet, final SessionImplementor session, final QueryParameters queryParameters, final boolean returnProxies) throws HibernateException { final int entitySpan = getEntityPersisters().length; final List hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan ); final Object result; try { result = getRowFromResultSet( resultSet, session, queryParameters, getLockModes( queryParameters.getLockModes() ), null, hydratedObjects, new EntityKey[entitySpan], returnProxies ); } catch ( SQLException sqle ) { throw JDBCExceptionHelper.convert( factory.getSQLExceptionConverter(), sqle, "could not read next row of results", getSQLString() ); } initializeEntitiesAndCollections( hydratedObjects, resultSet, session, queryParameters.isReadOnly() ); session.getPersistenceContext().initializeNonLazyCollections(); return result; } private Object sequentialLoad( final ResultSet resultSet, final SessionImplementor session, final QueryParameters queryParameters, final boolean returnProxies, final EntityKey keyToRead) throws HibernateException { final int entitySpan = getEntityPersisters().length; final List hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan ); Object result = null; final EntityKey[] loadedKeys = new EntityKey[entitySpan]; try { do { Object loaded = getRowFromResultSet( resultSet, session, queryParameters, getLockModes( queryParameters.getLockModes() ), null, hydratedObjects, loadedKeys, returnProxies ); if ( result == null ) { result = loaded; } } while ( keyToRead.equals( loadedKeys[0] ) && resultSet.next() ); } catch ( SQLException sqle ) { throw JDBCExceptionHelper.convert( factory.getSQLExceptionConverter(), sqle, "could not perform sequential read of results (forward)", getSQLString() ); } initializeEntitiesAndCollections( hydratedObjects, resultSet, session, queryParameters.isReadOnly() ); session.getPersistenceContext().initializeNonLazyCollections(); return result; } /** * Loads a single logical row from the result set moving forward. This is the * processing used from the ScrollableResults where there were collection fetches * encountered; thus a single logical row may have multiple rows in the underlying * result set. * * @param resultSet The result set from which to do the load. * @param session The session from which the request originated. * @param queryParameters The query parameters specified by the user. * @param returnProxies Should proxies be generated * @return The loaded "row". * @throws HibernateException */ public Object loadSequentialRowsForward( final ResultSet resultSet, final SessionImplementor session, final QueryParameters queryParameters, final boolean returnProxies) throws HibernateException { // note that for sequential scrolling, we make the assumption that // the first persister element is the "root entity" try { if ( resultSet.isAfterLast() ) { // don't even bother trying to read further return null; } if ( resultSet.isBeforeFirst() ) { resultSet.next(); } // We call getKeyFromResultSet() here so that we can know the // key value upon which to perform the breaking logic. However, // it is also then called from getRowFromResultSet() which is certainly // not the most efficient. But the call here is needed, and there // currently is no other way without refactoring of the doQuery()/getRowFromResultSet() // methods final EntityKey currentKey = getKeyFromResultSet( 0, getEntityPersisters()[0], null, resultSet, session ); return sequentialLoad( resultSet, session, queryParameters, returnProxies, currentKey ); } catch ( SQLException sqle ) { throw JDBCExceptionHelper.convert( factory.getSQLExceptionConverter(), sqle, "could not perform sequential read of results (forward)", getSQLString() ); } } /** * Loads a single logical row from the result set moving forward. This is the * processing used from the ScrollableResults where there were collection fetches * encountered; thus a single logical row may have multiple rows in the underlying * result set. * * @param resultSet The result set from which to do the load. * @param session The session from which the request originated. * @param queryParameters The query parameters specified by the user. * @param returnProxies Should proxies be generated * @return The loaded "row". * @throws HibernateException */ public Object loadSequentialRowsReverse( final ResultSet resultSet, final SessionImplementor session, final QueryParameters queryParameters, final boolean returnProxies, final boolean isLogicallyAfterLast) throws HibernateException {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -