📄 loader.java
字号:
//$Id: Loader.java 10139 2006-07-24 13:19:38Z max.andersen@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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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 Log log = LogFactory.getLog( 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
*/
protected abstract String getSQLString();
/**
* An array of persisters of entity classes contained in each row of results;
* implemented by all subclasses
*/
protected abstract Loadable[] getEntityPersisters();
/**
* An array indicating whether the entities have eager property fetching
* enabled
*/
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")
*/
protected int[] getOwners() {
return null;
}
/**
* An array of unique key property names by which the corresponding
* entities are referenced by other entities in the result set
*/
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 {
// note that for sequential scrolling, we make the assumption that
// the first persister element is the "root entity"
try {
if ( resultSet.isFirst() ) {
// don't even bother trying to read any further
return null;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -