HHH-7402 - Improve performance of named query registry
This commit is contained in:
parent
dc193c32c5
commit
7d99ca57f3
|
@ -251,4 +251,23 @@ public class NamedQueryDefinition implements Serializable {
|
|||
public String toString() {
|
||||
return getClass().getName() + '(' + name + " [" + query + "])";
|
||||
}
|
||||
|
||||
public NamedQueryDefinition makeCopy(String name) {
|
||||
return new NamedQueryDefinition(
|
||||
name,
|
||||
getQuery(),
|
||||
isCacheable(),
|
||||
getCacheRegion(),
|
||||
getTimeout(),
|
||||
getLockOptions(),
|
||||
getFetchSize(),
|
||||
getFlushMode(),
|
||||
getCacheMode(),
|
||||
isReadOnly(),
|
||||
getComment(),
|
||||
getParameterTypes(),
|
||||
getFirstResult(),
|
||||
getMaxResults()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,4 +216,27 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition {
|
|||
public String getResultSetRef() {
|
||||
return resultSetRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedSQLQueryDefinition makeCopy(String name) {
|
||||
return new NamedSQLQueryDefinition(
|
||||
name,
|
||||
getQuery(),
|
||||
isCacheable(),
|
||||
getCacheRegion(),
|
||||
getTimeout(),
|
||||
getFetchSize(),
|
||||
getFlushMode(),
|
||||
getCacheMode(),
|
||||
isReadOnly(),
|
||||
getComment(),
|
||||
getParameterTypes(),
|
||||
getFirstResult(),
|
||||
getMaxResults(),
|
||||
getResultSetRef(),
|
||||
getQuerySpaces(),
|
||||
isCallable(),
|
||||
getQueryReturns()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@ import org.hibernate.engine.profile.FetchProfile;
|
|||
import org.hibernate.engine.query.spi.QueryPlanCache;
|
||||
import org.hibernate.exception.spi.SQLExceptionConverter;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.internal.NamedQueryRepository;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
|
@ -281,4 +282,11 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
|
|||
public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy();
|
||||
|
||||
public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver();
|
||||
|
||||
/**
|
||||
* Provides access to the named query repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public NamedQueryRepository getNamedQueryRepository();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.ResultSetMappingDefinition;
|
||||
import org.hibernate.engine.query.spi.QueryPlanCache;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
|
||||
import org.hibernate.engine.spi.NamedQueryDefinition;
|
||||
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NamedQueryRepository {
|
||||
private static final Logger log = Logger.getLogger( NamedQueryRepository.class );
|
||||
|
||||
private volatile Map<String, NamedQueryDefinition> namedQueryDefinitionMap;
|
||||
private volatile Map<String, NamedSQLQueryDefinition> namedSqlQueryDefinitionMap;
|
||||
private final Map<String, ResultSetMappingDefinition> namedSqlResultSetMappingMap;
|
||||
|
||||
public NamedQueryRepository(
|
||||
Iterable<NamedQueryDefinition> namedQueryDefinitions,
|
||||
Iterable<NamedSQLQueryDefinition> namedSqlQueryDefinitions,
|
||||
Iterable<ResultSetMappingDefinition> namedSqlResultSetMappings) {
|
||||
final HashMap<String, NamedQueryDefinition> namedQueryDefinitionMap = new HashMap<String, NamedQueryDefinition>();
|
||||
for ( NamedQueryDefinition namedQueryDefinition : namedQueryDefinitions ) {
|
||||
namedQueryDefinitionMap.put( namedQueryDefinition.getName(), namedQueryDefinition );
|
||||
}
|
||||
this.namedQueryDefinitionMap = Collections.unmodifiableMap( namedQueryDefinitionMap );
|
||||
|
||||
|
||||
final HashMap<String, NamedSQLQueryDefinition> namedSqlQueryDefinitionMap = new HashMap<String, NamedSQLQueryDefinition>();
|
||||
for ( NamedSQLQueryDefinition namedSqlQueryDefinition : namedSqlQueryDefinitions ) {
|
||||
namedSqlQueryDefinitionMap.put( namedSqlQueryDefinition.getName(), namedSqlQueryDefinition );
|
||||
}
|
||||
this.namedSqlQueryDefinitionMap = Collections.unmodifiableMap( namedSqlQueryDefinitionMap );
|
||||
|
||||
final HashMap<String, ResultSetMappingDefinition> namedSqlResultSetMappingMap = new HashMap<String, ResultSetMappingDefinition>();
|
||||
for ( ResultSetMappingDefinition resultSetMappingDefinition : namedSqlResultSetMappings ) {
|
||||
namedSqlResultSetMappingMap.put( resultSetMappingDefinition.getName(), resultSetMappingDefinition );
|
||||
}
|
||||
this.namedSqlResultSetMappingMap = Collections.unmodifiableMap( namedSqlResultSetMappingMap );
|
||||
}
|
||||
|
||||
|
||||
public NamedQueryDefinition getNamedQueryDefinition(String queryName) {
|
||||
return namedQueryDefinitionMap.get( queryName );
|
||||
}
|
||||
|
||||
public NamedSQLQueryDefinition getNamedSQLQueryDefinition(String queryName) {
|
||||
return namedSqlQueryDefinitionMap.get( queryName );
|
||||
}
|
||||
|
||||
public ResultSetMappingDefinition getResultSetMappingDefinition(String mappingName) {
|
||||
return namedSqlResultSetMappingMap.get( mappingName );
|
||||
}
|
||||
|
||||
public synchronized void registerNamedQueryDefinition(String name, NamedQueryDefinition definition) {
|
||||
if ( NamedSQLQueryDefinition.class.isInstance( definition ) ) {
|
||||
throw new IllegalArgumentException( "NamedSQLQueryDefinition instance incorrectly passed to registerNamedQueryDefinition" );
|
||||
}
|
||||
|
||||
if ( ! name.equals( definition.getName() ) ) {
|
||||
definition = definition.makeCopy( name );
|
||||
}
|
||||
|
||||
final Map<String, NamedQueryDefinition> copy = CollectionHelper.makeCopy( namedQueryDefinitionMap );
|
||||
final NamedQueryDefinition previous = copy.put( name, definition );
|
||||
if ( previous != null ) {
|
||||
log.debugf(
|
||||
"registering named query definition [%s] overriding previously registered definition [%s]",
|
||||
name,
|
||||
previous
|
||||
);
|
||||
}
|
||||
|
||||
this.namedQueryDefinitionMap = Collections.unmodifiableMap( copy );
|
||||
}
|
||||
|
||||
public synchronized void registerNamedSQLQueryDefinition(String name, NamedSQLQueryDefinition definition) {
|
||||
if ( ! name.equals( definition.getName() ) ) {
|
||||
definition = definition.makeCopy( name );
|
||||
}
|
||||
|
||||
final Map<String, NamedSQLQueryDefinition> copy = CollectionHelper.makeCopy( namedSqlQueryDefinitionMap );
|
||||
final NamedQueryDefinition previous = copy.put( name, definition );
|
||||
if ( previous != null ) {
|
||||
log.debugf(
|
||||
"registering named SQL query definition [%s] overriding previously registered definition [%s]",
|
||||
name,
|
||||
previous
|
||||
);
|
||||
}
|
||||
|
||||
this.namedSqlQueryDefinitionMap = Collections.unmodifiableMap( copy );
|
||||
}
|
||||
|
||||
public Map<String,HibernateException> checkNamedQueries(QueryPlanCache queryPlanCache) {
|
||||
Map<String,HibernateException> errors = new HashMap<String,HibernateException>();
|
||||
|
||||
// Check named HQL queries
|
||||
log.debugf( "Checking %s named HQL queries", namedQueryDefinitionMap.size() );
|
||||
for ( NamedQueryDefinition namedQueryDefinition : namedQueryDefinitionMap.values() ) {
|
||||
// this will throw an error if there's something wrong.
|
||||
try {
|
||||
log.debugf( "Checking named query: %s", namedQueryDefinition.getName() );
|
||||
//TODO: BUG! this currently fails for named queries for non-POJO entities
|
||||
queryPlanCache.getHQLQueryPlan( namedQueryDefinition.getQueryString(), false, Collections.EMPTY_MAP );
|
||||
}
|
||||
catch ( HibernateException e ) {
|
||||
errors.put( namedQueryDefinition.getName(), e );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Check native-sql queries
|
||||
log.debugf( "Checking %s named SQL queries", namedSqlQueryDefinitionMap.size() );
|
||||
for ( NamedSQLQueryDefinition namedSQLQueryDefinition : namedSqlQueryDefinitionMap.values() ) {
|
||||
// this will throw an error if there's something wrong.
|
||||
try {
|
||||
log.debugf( "Checking named SQL query: %s", namedSQLQueryDefinition.getName() );
|
||||
// TODO : would be really nice to cache the spec on the query-def so as to not have to re-calc the hash;
|
||||
// currently not doable though because of the resultset-ref stuff...
|
||||
NativeSQLQuerySpecification spec;
|
||||
if ( namedSQLQueryDefinition.getResultSetRef() != null ) {
|
||||
ResultSetMappingDefinition definition = getResultSetMappingDefinition( namedSQLQueryDefinition.getResultSetRef() );
|
||||
if ( definition == null ) {
|
||||
throw new MappingException( "Unable to find resultset-ref definition: " + namedSQLQueryDefinition.getResultSetRef() );
|
||||
}
|
||||
spec = new NativeSQLQuerySpecification(
|
||||
namedSQLQueryDefinition.getQueryString(),
|
||||
definition.getQueryReturns(),
|
||||
namedSQLQueryDefinition.getQuerySpaces()
|
||||
);
|
||||
}
|
||||
else {
|
||||
spec = new NativeSQLQuerySpecification(
|
||||
namedSQLQueryDefinition.getQueryString(),
|
||||
namedSQLQueryDefinition.getQueryReturns(),
|
||||
namedSQLQueryDefinition.getQuerySpaces()
|
||||
);
|
||||
}
|
||||
queryPlanCache.getNativeSQLQueryPlan( spec );
|
||||
}
|
||||
catch ( HibernateException e ) {
|
||||
errors.put( namedSQLQueryDefinition.getName(), e );
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
|
@ -191,9 +191,7 @@ public final class SessionFactoryImpl
|
|||
private final transient Map<String,CollectionMetadata> collectionMetadata;
|
||||
private final transient Map<String,Set<String>> collectionRolesByEntityParticipant;
|
||||
private final transient Map<String,IdentifierGenerator> identifierGenerators;
|
||||
private final transient Map<String, NamedQueryDefinition> namedQueries;
|
||||
private final transient Map<String, NamedSQLQueryDefinition> namedSqlQueries;
|
||||
private final transient Map<String, ResultSetMappingDefinition> sqlResultSetMappings;
|
||||
private final transient NamedQueryRepository namedQueryRepository;
|
||||
private final transient Map<String, FilterDefinition> filters;
|
||||
private final transient Map<String, FetchProfile> fetchProfiles;
|
||||
private final transient Map<String,String> imports;
|
||||
|
@ -456,9 +454,11 @@ public final class SessionFactoryImpl
|
|||
collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap );
|
||||
|
||||
//Named Queries:
|
||||
namedQueries = new HashMap<String, NamedQueryDefinition>( cfg.getNamedQueries() );
|
||||
namedSqlQueries = new HashMap<String, NamedSQLQueryDefinition>( cfg.getNamedSQLQueries() );
|
||||
sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>( cfg.getSqlResultSetMappings() );
|
||||
this.namedQueryRepository = new NamedQueryRepository(
|
||||
cfg.getNamedQueries().values(),
|
||||
cfg.getNamedSQLQueries().values(),
|
||||
cfg.getSqlResultSetMappings().values()
|
||||
);
|
||||
imports = new HashMap<String,String>( cfg.getImports() );
|
||||
|
||||
// after *all* persisters and named queries are registered
|
||||
|
@ -845,19 +845,14 @@ public final class SessionFactoryImpl
|
|||
}
|
||||
collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap );
|
||||
|
||||
|
||||
//Named Queries:
|
||||
namedQueries = new HashMap<String,NamedQueryDefinition>();
|
||||
for ( NamedQueryDefinition namedQueryDefinition : metadata.getNamedQueryDefinitions() ) {
|
||||
namedQueries.put( namedQueryDefinition.getName(), namedQueryDefinition );
|
||||
}
|
||||
namedSqlQueries = new HashMap<String, NamedSQLQueryDefinition>();
|
||||
for ( NamedSQLQueryDefinition namedNativeQueryDefinition: metadata.getNamedNativeQueryDefinitions() ) {
|
||||
namedSqlQueries.put( namedNativeQueryDefinition.getName(), namedNativeQueryDefinition );
|
||||
}
|
||||
sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
|
||||
for( ResultSetMappingDefinition resultSetMappingDefinition : metadata.getResultSetMappingDefinitions() ) {
|
||||
sqlResultSetMappings.put( resultSetMappingDefinition.getName(), resultSetMappingDefinition );
|
||||
}
|
||||
namedQueryRepository = new NamedQueryRepository(
|
||||
metadata.getNamedQueryDefinitions(),
|
||||
metadata.getNamedNativeQueryDefinitions(),
|
||||
metadata.getResultSetMappingDefinitions()
|
||||
);
|
||||
|
||||
imports = new HashMap<String,String>();
|
||||
for ( Map.Entry<String,String> importEntry : metadata.getImports() ) {
|
||||
imports.put( importEntry.getKey(), importEntry.getValue() );
|
||||
|
@ -1058,78 +1053,8 @@ public final class SessionFactoryImpl
|
|||
return queryPlanCache;
|
||||
}
|
||||
|
||||
@SuppressWarnings( {"ThrowableResultOfMethodCallIgnored"})
|
||||
private Map<String,HibernateException> checkNamedQueries() throws HibernateException {
|
||||
Map<String,HibernateException> errors = new HashMap<String,HibernateException>();
|
||||
|
||||
// Check named HQL queries
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Checking %s named HQL queries", namedQueries.size() );
|
||||
}
|
||||
Iterator itr = namedQueries.entrySet().iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
final Map.Entry entry = ( Map.Entry ) itr.next();
|
||||
final String queryName = ( String ) entry.getKey();
|
||||
final NamedQueryDefinition qd = ( NamedQueryDefinition ) entry.getValue();
|
||||
// this will throw an error if there's something wrong.
|
||||
try {
|
||||
LOG.debugf( "Checking named query: %s", queryName );
|
||||
//TODO: BUG! this currently fails for named queries for non-POJO entities
|
||||
queryPlanCache.getHQLQueryPlan( qd.getQueryString(), false, Collections.EMPTY_MAP );
|
||||
}
|
||||
catch ( QueryException e ) {
|
||||
errors.put( queryName, e );
|
||||
}
|
||||
catch ( MappingException e ) {
|
||||
errors.put( queryName, e );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Checking %s named SQL queries", namedSqlQueries.size() );
|
||||
}
|
||||
itr = namedSqlQueries.entrySet().iterator();
|
||||
while ( itr.hasNext() ) {
|
||||
final Map.Entry entry = ( Map.Entry ) itr.next();
|
||||
final String queryName = ( String ) entry.getKey();
|
||||
final NamedSQLQueryDefinition qd = ( NamedSQLQueryDefinition ) entry.getValue();
|
||||
// this will throw an error if there's something wrong.
|
||||
try {
|
||||
LOG.debugf( "Checking named SQL query: %s", queryName );
|
||||
// TODO : would be really nice to cache the spec on the query-def so as to not have to re-calc the hash;
|
||||
// currently not doable though because of the resultset-ref stuff...
|
||||
NativeSQLQuerySpecification spec;
|
||||
if ( qd.getResultSetRef() != null ) {
|
||||
ResultSetMappingDefinition definition = sqlResultSetMappings.get( qd.getResultSetRef() );
|
||||
if ( definition == null ) {
|
||||
throw new MappingException( "Unable to find resultset-ref definition: " + qd.getResultSetRef() );
|
||||
}
|
||||
spec = new NativeSQLQuerySpecification(
|
||||
qd.getQueryString(),
|
||||
definition.getQueryReturns(),
|
||||
qd.getQuerySpaces()
|
||||
);
|
||||
}
|
||||
else {
|
||||
spec = new NativeSQLQuerySpecification(
|
||||
qd.getQueryString(),
|
||||
qd.getQueryReturns(),
|
||||
qd.getQuerySpaces()
|
||||
);
|
||||
}
|
||||
queryPlanCache.getNativeSQLQueryPlan( spec );
|
||||
}
|
||||
catch ( QueryException e ) {
|
||||
errors.put( queryName, e );
|
||||
}
|
||||
catch ( MappingException e ) {
|
||||
errors.put( queryName, e );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return errors;
|
||||
return namedQueryRepository.checkNamedQueries( queryPlanCache );
|
||||
}
|
||||
|
||||
public EntityPersister getEntityPersister(String entityName) throws MappingException {
|
||||
|
@ -1206,41 +1131,29 @@ public final class SessionFactoryImpl
|
|||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedQueryRepository getNamedQueryRepository() {
|
||||
return namedQueryRepository;
|
||||
}
|
||||
|
||||
public void registerNamedQueryDefinition(String name, NamedQueryDefinition definition) {
|
||||
if ( NamedSQLQueryDefinition.class.isInstance( definition ) ) {
|
||||
throw new IllegalArgumentException( "NamedSQLQueryDefinition instance incorrectly passed to registerNamedQueryDefinition" );
|
||||
}
|
||||
final NamedQueryDefinition previous = namedQueries.put( name, definition );
|
||||
if ( previous != null ) {
|
||||
LOG.debugf(
|
||||
"registering named query definition [%s] overriding previously registered definition [%s]",
|
||||
name,
|
||||
previous
|
||||
);
|
||||
}
|
||||
namedQueryRepository.registerNamedQueryDefinition( name, definition );
|
||||
}
|
||||
|
||||
public NamedQueryDefinition getNamedQuery(String queryName) {
|
||||
return namedQueries.get( queryName );
|
||||
return namedQueryRepository.getNamedQueryDefinition( queryName );
|
||||
}
|
||||
|
||||
public void registerNamedSQLQueryDefinition(String name, NamedSQLQueryDefinition definition) {
|
||||
final NamedSQLQueryDefinition previous = namedSqlQueries.put( name, definition );
|
||||
if ( previous != null ) {
|
||||
LOG.debugf(
|
||||
"registering named SQL query definition [%s] overriding previously registered definition [%s]",
|
||||
name,
|
||||
previous
|
||||
);
|
||||
}
|
||||
namedQueryRepository.registerNamedSQLQueryDefinition( name, definition );
|
||||
}
|
||||
|
||||
public NamedSQLQueryDefinition getNamedSQLQuery(String queryName) {
|
||||
return namedSqlQueries.get( queryName );
|
||||
return namedQueryRepository.getNamedSQLQueryDefinition( queryName );
|
||||
}
|
||||
|
||||
public ResultSetMappingDefinition getResultSetMapping(String resultSetName) {
|
||||
return sqlResultSetMappings.get( resultSetName );
|
||||
public ResultSetMappingDefinition getResultSetMapping(String mappingName) {
|
||||
return namedQueryRepository.getResultSetMappingDefinition( mappingName );
|
||||
}
|
||||
|
||||
public Type getIdentifierType(String className) throws MappingException {
|
||||
|
|
|
@ -146,4 +146,10 @@ public final class CollectionHelper {
|
|||
public static boolean isNotEmpty(Map map) {
|
||||
return !isEmpty( map );
|
||||
}
|
||||
|
||||
public static <X,Y> Map<X, Y> makeCopy(Map<X, Y> map) {
|
||||
final Map<X,Y> copy = mapOfSize( map.size() + 1 );
|
||||
copy.putAll( map );
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue