Package org.hibernate.loader.entity

Source Code of org.hibernate.loader.entity.DynamicBatchingEntityLoaderBuilder$DynamicEntityLoader

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.loader.entity;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.spi.AfterLoadAction;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.pretty.MessageHelper;

import org.jboss.logging.Logger;

/**
* A BatchingEntityLoaderBuilder that builds UniqueEntityLoader instances capable of dynamically building
* its batch-fetch SQL based on the actual number of entity ids waiting to be fetched.
*
* @author Steve Ebersole
*/
public class DynamicBatchingEntityLoaderBuilder extends BatchingEntityLoaderBuilder {
  private static final Logger log = Logger.getLogger( DynamicBatchingEntityLoaderBuilder.class );

  public static final DynamicBatchingEntityLoaderBuilder INSTANCE = new DynamicBatchingEntityLoaderBuilder();

  @Override
  protected UniqueEntityLoader buildBatchingLoader(
      OuterJoinLoadable persister,
      int batchSize,
      LockMode lockMode,
      SessionFactoryImplementor factory,
      LoadQueryInfluencers influencers) {
    return new DynamicBatchingEntityLoader( persister, batchSize, lockMode, factory, influencers );
  }

  @Override
  protected UniqueEntityLoader buildBatchingLoader(
      OuterJoinLoadable persister,
      int batchSize,
      LockOptions lockOptions,
      SessionFactoryImplementor factory,
      LoadQueryInfluencers influencers) {
    return new DynamicBatchingEntityLoader( persister, batchSize, lockOptions, factory, influencers );
  }

  public static class DynamicBatchingEntityLoader extends BatchingEntityLoader {
    private final int maxBatchSize;
    private final UniqueEntityLoader singleKeyLoader;
    private final DynamicEntityLoader dynamicLoader;

    public DynamicBatchingEntityLoader(
        OuterJoinLoadable persister,
        int maxBatchSize,
        LockMode lockMode,
        SessionFactoryImplementor factory,
        LoadQueryInfluencers loadQueryInfluencers) {
      super( persister );
      this.maxBatchSize = maxBatchSize;
      this.singleKeyLoader = new EntityLoader( persister, 1, lockMode, factory, loadQueryInfluencers );
      this.dynamicLoader = new DynamicEntityLoader( persister, maxBatchSize, lockMode, factory, loadQueryInfluencers );
    }

    public DynamicBatchingEntityLoader(
        OuterJoinLoadable persister,
        int maxBatchSize,
        LockOptions lockOptions,
        SessionFactoryImplementor factory,
        LoadQueryInfluencers loadQueryInfluencers) {
      super( persister );
      this.maxBatchSize = maxBatchSize;
      this.singleKeyLoader = new EntityLoader( persister, 1, lockOptions, factory, loadQueryInfluencers );
      this.dynamicLoader = new DynamicEntityLoader( persister, maxBatchSize, lockOptions, factory, loadQueryInfluencers );
    }

    @Override
    public Object load(
        Serializable id,
        Object optionalObject,
        SessionImplementor session,
        LockOptions lockOptions) {
      final Serializable[] batch = session.getPersistenceContext()
          .getBatchFetchQueue()
          .getEntityBatch( persister(), id, maxBatchSize, persister().getEntityMode() );

      final int numberOfIds = ArrayHelper.countNonNull( batch );
      if ( numberOfIds <= 1 ) {
        return singleKeyLoader.load( id, optionalObject, session );
      }

      final Serializable[] idsToLoad = new Serializable[numberOfIds];
      System.arraycopy( batch, 0, idsToLoad, 0, numberOfIds );

      if ( log.isDebugEnabled() ) {
        log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister(), idsToLoad, session.getFactory() ) );
      }

      QueryParameters qp = buildQueryParameters( id, idsToLoad, optionalObject, lockOptions );
      List results = dynamicLoader.doEntityBatchFetch( session, qp, idsToLoad );
      return getObjectFromList( results, id, session );
    }
  }


  private static class DynamicEntityLoader extends EntityLoader {
    // todo : see the discussion on org.hibernate.loader.collection.DynamicBatchingCollectionInitializerBuilder.DynamicBatchingCollectionLoader

    private final String sqlTemplate;
    private final String alias;

    public DynamicEntityLoader(
        OuterJoinLoadable persister,
        int maxBatchSize,
        LockOptions lockOptions,
        SessionFactoryImplementor factory,
        LoadQueryInfluencers loadQueryInfluencers) {
      this( persister, maxBatchSize, lockOptions.getLockMode(), factory, loadQueryInfluencers );
    }

    public DynamicEntityLoader(
        OuterJoinLoadable persister,
        int maxBatchSize,
        LockMode lockMode,
        SessionFactoryImplementor factory,
        LoadQueryInfluencers loadQueryInfluencers) {
      super( persister, -1, lockMode, factory, loadQueryInfluencers );

      EntityJoinWalker walker = new EntityJoinWalker(
          persister,
          persister.getIdentifierColumnNames(),
          -1,
          lockMode,
          factory,
          loadQueryInfluencers
      ) {
        @Override
        protected StringBuilder whereString(String alias, String[] columnNames, int batchSize) {
          return StringHelper.buildBatchFetchRestrictionFragment( alias, columnNames, getFactory().getDialect() );
        }
      };

      initFromWalker( walker );
      this.sqlTemplate = walker.getSQLString();
      this.alias = walker.getAlias();
      postInstantiate();

      if ( LOG.isDebugEnabled() ) {
        LOG.debugf(
            "SQL-template for dynamic entity [%s] batch-fetching [%s] : %s",
            entityName,
            lockMode,
            sqlTemplate
        );
      }
    }

    @Override
    protected boolean isSingleRowLoader() {
      return false;
    }

    public List doEntityBatchFetch(
        SessionImplementor session,
        QueryParameters queryParameters,
        Serializable[] ids) {
      final String sql = StringHelper.expandBatchIdPlaceholder(
          sqlTemplate,
          ids,
          alias,
          persister.getKeyColumnNames(),
          getFactory().getDialect()
      );

      try {
        final PersistenceContext persistenceContext = session.getPersistenceContext();
        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();
        List results;
        try {
          try {
            results = doTheLoad( sql, queryParameters, session );
          }
          finally {
            persistenceContext.afterLoad();
          }
          persistenceContext.initializeNonLazyCollections();
          log.debug( "Done batch load" );
          return results;
        }
        finally {
          // Restore the original default
          persistenceContext.setDefaultReadOnly( defaultReadOnlyOrig );
        }
      }
      catch ( SQLException sqle ) {
        throw session.getFactory().getSQLExceptionHelper().convert(
            sqle,
            "could not load an entity batch: " + MessageHelper.infoString(
                getEntityPersisters()[0],
                ids,
                session.getFactory()
            ),
            sql
        );
      }
    }

    private List doTheLoad(String sql, QueryParameters queryParameters, SessionImplementor session) throws SQLException {
      final RowSelection selection = queryParameters.getRowSelection();
      final int maxRows = LimitHelper.hasMaxRows( selection ) ?
          selection.getMaxRows() :
          Integer.MAX_VALUE;

      final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
      final SqlStatementWrapper wrapper = executeQueryStatement( sql, queryParameters, false, afterLoadActions, session );
      final ResultSet rs = wrapper.getResultSet();
      final Statement st = wrapper.getStatement();
      try {
        return processResultSet( rs, queryParameters, session, false, null, maxRows, afterLoadActions );
      }
      finally {
        session.getTransactionCoordinator().getJdbcCoordinator().release( st );
      }
    }
  }
}
TOP

Related Classes of org.hibernate.loader.entity.DynamicBatchingEntityLoaderBuilder$DynamicEntityLoader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.