hjjae2 / anything

:fire: anything
2 stars 0 forks source link

QueryExecutorMethodInterceptor #14

Open hjjae2 opened 2 years ago

hjjae2 commented 2 years ago
image

EventListnerGroupImpl.fireEventOnListener()

DefulatLoadEventListener.onLoad

DefulatLoadEventListener.doOnLoad

    private void doOnLoad(
            final EntityPersister persister,
            final LoadEvent event,
            final LoadEventListener.LoadType loadType) {

        try {
            final EventSource session = event.getSession();
            final EntityKey keyToLoad = session.generateEntityKey( event.getEntityId(), persister );
            if ( loadType.isNakedEntityReturned() ) {
                //do not return a proxy!
                //(this option indicates we are initializing a proxy)
                event.setResult( load( event, persister, keyToLoad, loadType ) );
            }
            else {
                //return a proxy if appropriate
                if ( event.getLockMode() == LockMode.NONE ) {
                    event.setResult( proxyOrLoad( event, persister, keyToLoad, loadType ) );
                }
                else {
                    event.setResult( lockAndLoad( event, persister, keyToLoad, loadType, session ) );
                }
            }
        }
        catch (HibernateException e) {
            LOG.unableToLoadCommand( e );
            throw e;
        }
    }
        // 1차 캐시?
    private Object proxyOrLoad(
            final LoadEvent event,
            final EntityPersister persister,
            final EntityKey keyToLoad,
            final LoadEventListener.LoadType options) {

        final EventSource session = event.getSession();
        final SessionFactoryImplementor factory = session.getFactory();
        final boolean traceEnabled = LOG.isTraceEnabled();

        if ( traceEnabled ) {
            LOG.tracev(
                    "Loading entity: {0}",
                    MessageHelper.infoString( persister, event.getEntityId(), factory )
            );
        }

        final PersistenceContext persistenceContext = session.getPersistenceContextInternal();

        final EntityMetamodel entityMetamodel = persister.getEntityMetamodel();
        final boolean entityHasHibernateProxyFactory = entityMetamodel
                .getTuplizer()
                .getProxyFactory() != null;

        // Check for the case where we can use the entity itself as a proxy
        if ( options.isAllowProxyCreation()
                && entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) {
            // if there is already a managed entity instance associated with the PC, return it
            final Object managed = persistenceContext.getEntity( keyToLoad );
            if ( managed != null ) {
                if ( options.isCheckDeleted() ) {
                    final EntityEntry entry = persistenceContext.getEntry( managed );
                    final Status status = entry.getStatus();
                    if ( status == Status.DELETED || status == Status.GONE ) {
                        return null;
                    }
                }
                return managed;
            }

            // if the entity defines a HibernateProxy factory, see if there is an
            // existing proxy associated with the PC - and if so, use it
            if ( entityHasHibernateProxyFactory ) {
                final Object proxy = persistenceContext.getProxy( keyToLoad );

                if ( proxy != null ) {
                    if( traceEnabled ) {
                        LOG.trace( "Entity proxy found in session cache" );
                    }

                    if ( LOG.isDebugEnabled() && ( (HibernateProxy) proxy ).getHibernateLazyInitializer().isUnwrap() ) {
                        LOG.debug( "Ignoring NO_PROXY to honor laziness" );
                    }

                    return persistenceContext.narrowProxy( proxy, persister, keyToLoad, null );
                }

                // specialized handling for entities with subclasses with a HibernateProxy factory
                if ( entityMetamodel.hasSubclasses() ) {
                    // entities with subclasses that define a ProxyFactory can create a HibernateProxy
                    return createProxy( event, persister, keyToLoad, persistenceContext );
                }
            }
            if ( !entityMetamodel.hasSubclasses() ) {
                if ( keyToLoad.isBatchLoadable() ) {
                    // Add a batch-fetch entry into the queue for this entity
                    persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
                }

                // This is the crux of HHH-11147
                // create the (uninitialized) entity instance - has only id set
                return persister.getBytecodeEnhancementMetadata().createEnhancedProxy( keyToLoad, true, session );
            }
            // If we get here, then the entity class has subclasses and there is no HibernateProxy factory.
            // The entity will get loaded below.
        }
        else {
            if ( persister.hasProxy() ) {
                // look for a proxy
                Object proxy = persistenceContext.getProxy( keyToLoad );
                if ( proxy != null ) {
                    return returnNarrowedProxy( event, persister, keyToLoad, options, persistenceContext, proxy );
                }

                if ( options.isAllowProxyCreation() ) {
                    return createProxyIfNecessary( event, persister, keyToLoad, options, persistenceContext );
                }
            }
        }

        // return a newly loaded object
        return load( event, persister, keyToLoad, options );
    }

DefulatLoadEventListener.load

    private Object load(
            final LoadEvent event,
            final EntityPersister persister,
            final EntityKey keyToLoad,
            final LoadEventListener.LoadType options) {

        final EventSource session = event.getSession();
        if ( event.getInstanceToLoad() != null ) {
            if ( session.getPersistenceContextInternal().getEntry( event.getInstanceToLoad() ) != null ) {
                throw new PersistentObjectException(
                        "attempted to load into an instance that was already associated with the session: " +
                                MessageHelper.infoString(
                                        persister,
                                        event.getEntityId(),
                                        session.getFactory()
                                )
                );
            }
            persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), session);
        }

        final Object entity = doLoad( event, persister, keyToLoad, options ); // StatefulPersistenceContext.doLoad()

        boolean isOptionalInstance = event.getInstanceToLoad() != null;

        if ( entity == null && ( !options.isAllowNulls() || isOptionalInstance ) ) {
            session
                    .getFactory()
                    .getEntityNotFoundDelegate()
                    .handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
        }
        else if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
            throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
        }

        return entity;
    }

StatefulPersistenceContext.doLoad() ⭐ ⭐

    private Object doLoad(
            final LoadEvent event,
            final EntityPersister persister,
            final EntityKey keyToLoad,
            final LoadEventListener.LoadType options) {

        final EventSource session = event.getSession();
        final boolean traceEnabled = LOG.isTraceEnabled();
        if ( traceEnabled ) {
            LOG.tracev(
                    "Attempting to resolve: {0}",
                    MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() )
            );
        }

        CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.INSTANCE.loadFromSessionCache(
                event,
                keyToLoad,
                options
        );
        Object entity = persistenceContextEntry.getEntity();

        if ( entity != null ) {
            return persistenceContextEntry.isManaged() ? entity : null;
        }

        entity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( event, persister, keyToLoad );
        if ( entity != null ) {
            if ( traceEnabled ) {
                LOG.tracev(
                        "Resolved object in second-level cache: {0}",
                        MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() )
                );
            }
        }
        else {
            if ( traceEnabled ) {
                LOG.tracev(
                        "Object not resolved in any cache: {0}",
                        MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() )
                );
            }
            entity = loadFromDatasource( event, persister );
        }

        if ( entity != null && persister.hasNaturalIdentifier() ) {
            final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
            final PersistenceContext.NaturalIdHelper naturalIdHelper = persistenceContext.getNaturalIdHelper();
            naturalIdHelper.cacheNaturalIdCrossReferenceFromLoad(
                    persister,
                    event.getEntityId(),
                    naturalIdHelper.extractNaturalIdValues(
                            entity,
                            persister
                    )
            );
        }

        return entity;
    }

AbstractEntityPersister.load() -> AbstractEntityPersister.doLoad()

    private Object doLoad(Serializable id, Object optionalObject, LockOptions lockOptions, SharedSessionContractImplementor session, Boolean readOnly)
            throws HibernateException {
        if ( LOG.isTraceEnabled() ) {
            LOG.tracev( "Fetching entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
        }

        final UniqueEntityLoader loader = getAppropriateLoader( lockOptions, session );
        return loader.load( id, optionalObject, session, lockOptions, readOnly );
    }

AbstractLoadPlanBasedEntityLoader.load()

    public Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, LockOptions lockOptions, Boolean readOnly) {

        final Object result;
        try {
            final QueryParameters qp = new QueryParameters();
            qp.setPositionalParameterTypes( new Type[] { entityPersister.getIdentifierType() } );
            qp.setPositionalParameterValues( new Object[] { id } );
            qp.setOptionalObject( optionalObject );
            qp.setOptionalEntityName( entityPersister.getEntityName() );
            qp.setOptionalId( id );
            qp.setLockOptions( lockOptions );
            if ( readOnly != null ) {
                qp.setReadOnly( readOnly );
            }
            final List results = executeLoad(
                    session,
                    qp,
                    staticLoadQuery,
                    false,
                    null
            );
            result = extractEntityResult( results, id );
        }
        catch ( SQLException sqle ) {
            throw session.getJdbcServices().getSqlExceptionHelper().convert(
                    sqle,
                    "could not load an entity: " + MessageHelper.infoString(
                            entityPersister,
                            id,
                            entityPersister.getIdentifierType(),
                            getFactory()
                    ),
                    staticLoadQuery.getSqlStatement()
            );
        }

        log.debugf( "Done entity load : %s#%s", getEntityName(), id );
        return result;
    }

AbstractLoadPlanBasedLoader.executeLoad()

    protected List executeLoad(
            SharedSessionContractImplementor session,
            QueryParameters queryParameters,
            LoadQueryDetails loadQueryDetails,
            boolean returnProxies,
            ResultTransformer forcedResultTransformer) throws SQLException {
        final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
        final boolean defaultReadOnlyOrig = persistenceContext.isDefaultReadOnly();
        if ( queryParameters.isReadOnlyInitialized() ) {
            // The read-only/modifiable mode for the query was explicitly set.
            // Temporarily set the default read-only/modifiable setting to the query's setting.
            persistenceContext.setDefaultReadOnly( queryParameters.isReadOnly() );
        }
        else {
            // The read-only/modifiable setting for the query was not initialized.
            // Use the default read-only/modifiable from the persistence context instead.
            queryParameters.setReadOnly( persistenceContext.isDefaultReadOnly() );
        }
        persistenceContext.beforeLoad();
        try {
            final List results;
            final String sql = loadQueryDetails.getSqlStatement();
            SqlStatementWrapper wrapper = null;
            try {
                wrapper = executeQueryStatement( sql, queryParameters, false, session );
                results = loadQueryDetails.getResultSetProcessor().extractResults(
                        wrapper.getResultSet(),
                        session,
                        queryParameters,
                        new NamedParameterContext() {
                            @Override
                            public int[] getNamedParameterLocations(String name) {
                                return AbstractLoadPlanBasedLoader.this.getNamedParameterLocs( name );
                            }
                        },
                        returnProxies,
                        queryParameters.isReadOnly(),
                        forcedResultTransformer,
                        Collections.EMPTY_LIST
                );
            }
            finally {
                if ( wrapper != null ) {
                    final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator();
                    final ResourceRegistry resourceRegistry = jdbcCoordinator.getResourceRegistry();
                    resourceRegistry.release( wrapper.getStatement() );
                    jdbcCoordinator.afterStatementExecution();
                }
                persistenceContext.afterLoad();
            }
            persistenceContext.initializeNonLazyCollections();
            return results;
        }
        finally {
            // Restore the original default
            persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig );
        }
    }

AbstractLoadPlanBasedLoader.executeQueryStatement()

    protected SqlStatementWrapper executeQueryStatement(
            String sqlStatement,
            QueryParameters queryParameters,
            boolean scroll,
            SharedSessionContractImplementor session) throws SQLException {

        // Processing query filters.
        queryParameters.processFilters( sqlStatement, session );

        // Applying LIMIT clause.
        final LimitHandler limitHandler = getLimitHandler(
                queryParameters.getRowSelection()
        );
        String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters );

        // Adding locks and comments.
        sql = session.getJdbcServices().getJdbcEnvironment().getDialect()
                .addSqlHintOrComment(
                    sql,
                    queryParameters,
                    session.getFactory().getSessionFactoryOptions().isCommentsEnabled()
                );

        final PreparedStatement st = prepareQueryStatement( sql, queryParameters, limitHandler, scroll, session );
        return new SqlStatementWrapper( st, getResultSet( st, queryParameters.getRowSelection(), limitHandler, queryParameters.hasAutoDiscoverScalarTypes(), session ) );
    }
hjjae2 commented 2 years ago
  1. 영속성 컨텍스트 구현체 : StatefulPersistenceContext
  2. 데이터 조회 순서 : 1차 캐시 , Session-Level Cache, 2차 캐시, Datasource 조회
  3. SelectStatementBuilder : select query 생성 빌더
  4. 디버깅 포인트 : SessionImpl.load(), AbstractLoadPlanBasedLoader.executeQueryStatement(), ... , SharedEntityManagerCreator, ...
  5. SimpleJpaRepository (Default implementation of the org.springframework.data.repository.CrudRepository interface.)