All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.engine.internal.TwoPhaseLoad Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha2
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.engine.internal;

import java.io.Serializable;

import org.hibernate.CacheMode;
import org.hibernate.LockMode;
import org.hibernate.annotations.Remove;
import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.model.domain.spi.EntityTypeDescriptor;

import org.jboss.logging.Logger;

/**
 * Functionality relating to the Hibernate two-phase loading process, that may be reused by descriptors
 * that do not use the Loader framework
 *
 * @author Gavin King
 *
 * @deprecated to be removed in 6.0 (this was always considered an internal class); two-phase loading is
 * handled via {@link org.hibernate.sql.results.spi.Initializer} and friends
 */
@Remove
@Deprecated
public final class TwoPhaseLoad {

	// todo (6.0) : remove this class

	private static final CoreMessageLogger LOG = Logger.getMessageLogger(
			CoreMessageLogger.class,
			TwoPhaseLoad.class.getName()
	);

	private TwoPhaseLoad() {
	}

	/**
	 * Register the "hydrated" state of an entity instance, after the first step of 2-phase loading.
	 *
	 * Add the "hydrated state" (an array) of an uninitialized entity to the session. We don't try
	 * to resolve any associations yet, because there might be other entities waiting to be
	 * read from the JDBC result set we are currently processing
	 *
	 * @param descriptor The descriptor for the hydrated entity
	 * @param id The entity identifier
	 * @param values The entity values
	 * @param rowId The rowId for the entity
	 * @param object An optional instance for the entity being loaded
	 * @param lockMode The lock mode
	 * @param session The Session
	 */
	public static void postHydrate(
			final EntityTypeDescriptor descriptor,
			final Serializable id,
			final Object[] values,
			final Object rowId,
			final Object object,
			final LockMode lockMode,
			final SharedSessionContractImplementor session) {
		final Object version = Versioning.getVersion( values, descriptor );
		session.getPersistenceContext().addEntry(
				object,
				Status.LOADING,
				values,
				rowId,
				id,
				version,
				lockMode,
				true,
				descriptor,
				false
			);

		if ( version != null && LOG.isTraceEnabled() ) {
			final String versionStr = descriptor.getHierarchy().getVersionDescriptor() != null
					? descriptor.getHierarchy().getVersionDescriptor().getJavaTypeDescriptor().extractLoggableRepresentation( version )
					: "null";
			LOG.tracef( "Version: %s", versionStr );
		}
	}

//	/**
//	 * Perform the second step of 2-phase load. Fully initialize the entity
//	 * instance.
//	 * 

// * After processing a JDBC result set, we "resolve" all the associations // * between the entities which were instantiated and had their state // * "hydrated" into an array // * // * @param entity The entity being loaded // * @param readOnly Is the entity being loaded as read-only // * @param session The Session // * @param preLoadEvent The (re-used) pre-load event // */ // public static void initializeEntity( // final Object entity, // final boolean readOnly, // final SharedSessionContractImplementor session, // final PreLoadEvent preLoadEvent) { // final PersistenceContext persistenceContext = session.getPersistenceContext(); // final EntityEntry entityEntry = persistenceContext.getEntry( entity ); // if ( entityEntry == null ) { // throw new AssertionFailure( "possible non-threadsafe access to the session" ); // } // doInitializeEntity( entity, entityEntry, readOnly, session, preLoadEvent ); // } // // private static void doInitializeEntity( // final Object entity, // final EntityEntry entityEntry, // final boolean readOnly, // final SharedSessionContractImplementor session, // final PreLoadEvent preLoadEvent) throws HibernateException { // final PersistenceContext persistenceContext = session.getPersistenceContext(); // final EntityPersister persister = entityEntry.getPersister(); // final Serializable id = entityEntry.getId(); // final Object[] hydratedState = entityEntry.getLoadedState(); // // final boolean debugEnabled = LOG.isDebugEnabled(); // if ( debugEnabled ) { // LOG.debugf( // "Resolving associations for %s", // MessageHelper.infoString( persister, id, session.getFactory() ) // ); // } // // String entityName = persister.getEntityName(); // String[] propertyNames = persister.getPropertyNames(); // final Type[] types = persister.getPropertyTypes(); // for ( int i = 0; i < hydratedState.length; i++ ) { // final Object value = hydratedState[i]; // // todo (6.0) - this "overriding eager" block was added in 5.x and we need to // // make sure that the logic makes it into the 6.0 solution as well. // Boolean overridingEager = getOverridingEager( session, entityName, propertyNames[i], types[i] ); // if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY ) { // // IMPLEMENTATION NOTE: This is a lazy property on a bytecode-enhanced entity. // // hydratedState[i] needs to remain LazyPropertyInitializer.UNFETCHED_PROPERTY so that // // setPropertyValues() below (ultimately AbstractEntityTuplizer#setPropertyValues) works properly // // No resolution is necessary, unless the lazy property is a collection. // if ( types[i].isCollectionType() ) { // // IMPLEMENTATION NOTE: this is a lazy collection property on a bytecode-enhanced entity. // // HHH-10989: We need to resolve the collection so that a CollectionReference is added to StatefulPersistentContext. // // As mentioned above, hydratedState[i] needs to remain LazyPropertyInitializer.UNFETCHED_PROPERTY // // so do not assign the resolved, unitialized PersistentCollection back to hydratedState[i]. // types[i].resolve( value, session, entity, overridingEager ); // } // } // else if ( value != PropertyAccessStrategyBackRefImpl.UNKNOWN ) { // // we know value != LazyPropertyInitializer.UNFETCHED_PROPERTY // hydratedState[i] = types[i].resolve( value, session, entity, overridingEager ); // } // } // // //Must occur after resolving identifiers! // if ( session.isEventSource() ) { // preLoadEvent.setEntity( entity ).setState( hydratedState ).setId( id ).setPersister( persister ); // // final EventListenerGroup listenerGroup = session // .getFactory() // .getServiceRegistry() // .getService( EventListenerRegistry.class ) // .getEventListenerGroup( EventType.PRE_LOAD ); // for ( PreLoadEventListener listener : listenerGroup.listeners() ) { // listener.onPreLoad( preLoadEvent ); // } // } // // persister.setPropertyValues( entity, hydratedState ); // // final SessionFactoryImplementor factory = session.getFactory(); // if ( persister.canWriteToCache() && session.getCacheMode().isPutEnabled() ) { // // if ( debugEnabled ) { // LOG.debugf( // "Adding entity to second-level cache: %s", // MessageHelper.infoString( persister, id, session.getFactory() ) // ); // } // // final Object version = Versioning.getVersion( hydratedState, persister ); // final CacheEntry entry = persister.buildCacheEntry( entity, hydratedState, version, session ); // final EntityDataAccess cache = persister.getCacheAccessStrategy(); // final Object cacheKey = cache.generateCacheKey( id, persister, factory, session.getTenantIdentifier() ); // // // explicit handling of caching for rows just inserted and then somehow forced to be read // // from the database *within the same transaction*. usually this is done by // // 1) Session#refresh, or // // 2) Session#clear + some form of load // // // // we need to be careful not to clobber the lock here in the cache so that it can be rolled back if need be // if ( session.getPersistenceContext().wasInsertedDuringTransaction( persister, id ) ) { // cache.update( // session, // cacheKey, // persister.getCacheEntryStructure().structure( entry ), // version, // version // ); // } // else { // final SessionEventListenerManager eventListenerManager = session.getEventListenerManager(); // try { // eventListenerManager.cachePutStart(); // final boolean put = cache.putFromLoad( // session, // cacheKey, // persister.getCacheEntryStructure().structure( entry ), // version, // useMinimalPuts( session, entityEntry ) // ); // // if ( put && factory.getStatistics().isStatisticsEnabled() ) { // factory.getStatistics().entityCachePut( // StatsHelper.INSTANCE.getRootEntityRole( persister ), // cache.getRegion().getName() // ); // } // } // finally { // eventListenerManager.cachePutEnd(); // } // } // } // // if ( persister.hasNaturalIdentifier() ) { // persistenceContext.getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad( // persister, // id, // persistenceContext.getNaturalIdHelper().extractNaturalIdValues( hydratedState, persister ) // ); // } // // boolean isReallyReadOnly = readOnly; // if ( !persister.isMutable() ) { // isReallyReadOnly = true; // } // else { // final Object proxy = persistenceContext.getProxy( entityEntry.getEntityKey() ); // if ( proxy != null ) { // // there is already a proxy for this impl // // only set the status to read-only if the proxy is read-only // isReallyReadOnly = ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isReadOnly(); // } // } // if ( isReallyReadOnly ) { // //no need to take a snapshot - this is a // //performance optimization, but not really // //important, except for entities with huge // //mutable property values // persistenceContext.setEntryStatus( entityEntry, Status.READ_ONLY ); // } // else { // //take a snapshot // TypeHelper.deepCopy( // hydratedState, // persister.getPropertyTypes(), // persister.getPropertyUpdateability(), // //after setting values to object // hydratedState, // session // ); // persistenceContext.setEntryStatus( entityEntry, Status.MANAGED ); // } // // if ( debugEnabled ) { // LOG.debugf( // "Done materializing entity %s", // MessageHelper.infoString( persister, id, session.getFactory() ) // ); // } // // if ( factory.getStatistics().isStatisticsEnabled() ) { // factory.getStatistics().loadEntity( persister.getEntityName() ); // } // } // // /** // * Perform the afterInitialize() step. This needs to be done after the collections have been properly initialized // * thus a separate step. // * // * @param entity The entity being loaded // * @param session The Session // */ // public static void afterInitialize( // final Object entity, // final SharedSessionContractImplementor session) { // final PersistenceContext persistenceContext = session.getPersistenceContext(); // final EntityEntry entityEntry = persistenceContext.getEntry( entity ); // // entityEntry.getPersister().afterInitialize( entity, session ); // } // // /** // * Check if eager of the association is overriden by anything. // * // * @param session session // * @param entityName entity name // * @param associationName association name // * // * @return null if there is no overriding, true if it is overridden to eager and false if it is overridden to lazy // */ // private static Boolean getOverridingEager( // SharedSessionContractImplementor session, // String entityName, // String associationName, // Type type) { // if ( type.isAssociationType() || type.isCollectionType() ) { // Boolean overridingEager = isEagerFetchProfile( session, entityName + "." + associationName ); // // if ( LOG.isDebugEnabled() ) { // if ( overridingEager != null ) { // LOG.debugf( // "Overriding eager fetching using active fetch profile. EntityName: %s, associationName: %s, eager fetching: %s", // entityName, // associationName, // overridingEager // ); // } // } // // return overridingEager; // } // return null; // } private static Boolean isEagerFetchProfile(SharedSessionContractImplementor session, String role) { LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); for ( String fetchProfileName : loadQueryInfluencers.getEnabledFetchProfileNames() ) { FetchProfile fp = session.getFactory().getFetchProfile( fetchProfileName ); Fetch fetch = fp.getFetchByRole( role ); if ( fetch != null && Fetch.Style.JOIN == fetch.getStyle() ) { return true; } } return null; } /** * PostLoad cannot occur during initializeEntity, as that call occurs *before* * the Set collections are added to the persistence context by Loader. * Without the split, LazyInitializationExceptions can occur in the Entity's * postLoad if it acts upon the collection. * * HHH-6043 * * @param entity The entity * @param session The Session * @param postLoadEvent The (re-used) post-load event */ public static void postLoad( final Object entity, final SharedSessionContractImplementor session, final PostLoadEvent postLoadEvent) { if ( session.isEventSource() ) { final PersistenceContext persistenceContext = session.getPersistenceContext(); final EntityEntry entityEntry = persistenceContext.getEntry( entity ); postLoadEvent.setEntity( entity ).setId( entityEntry.getId() ).setDescriptor( entityEntry.getDescriptor() ); final EventListenerGroup listenerGroup = session.getFactory() .getServiceRegistry() .getService( EventListenerRegistry.class ) .getEventListenerGroup( EventType.POST_LOAD ); for ( PostLoadEventListener listener : listenerGroup.listeners() ) { listener.onPostLoad( postLoadEvent ); } } } private static boolean useMinimalPuts(SharedSessionContractImplementor session, EntityEntry entityEntry) { if ( session.getFactory().getSessionFactoryOptions().isMinimalPutsEnabled() ) { return session.getCacheMode() != CacheMode.REFRESH; } else { return false; // return entityEntry.getDescriptor().hasLazyProperties() // && entityEntry.getDescriptor().isLazyPropertiesCacheable(); } } /** * Add an uninitialized instance of an entity class, as a placeholder to ensure object * identity. Must be called before postHydrate(). * * Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized, * but we need the mapping from id to instance in order to guarantee uniqueness. * * @param key The entity key * @param object The entity instance * @param descriptor The entity descriptor * @param lockMode The lock mode * @param session The Session */ public static void addUninitializedEntity( final EntityKey key, final Object object, final EntityTypeDescriptor descriptor, final LockMode lockMode, final SharedSessionContractImplementor session) { session.getPersistenceContext().addEntity( object, Status.LOADING, null, key, null, lockMode, true, descriptor, false ); } /** * Same as {@link #addUninitializedEntity}, but here for an entity from the second level cache * * @param key The entity key * @param object The entity instance * @param descriptor The entity descriptor * @param lockMode The lock mode * @param version The version * @param session The Session */ public static void addUninitializedCachedEntity( final EntityKey key, final Object object, final EntityTypeDescriptor descriptor, final LockMode lockMode, final Object version, final SharedSessionContractImplementor session) { session.getPersistenceContext().addEntity( object, Status.LOADING, null, key, version, lockMode, true, descriptor, false ); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy