Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

HHH-7402 - Improve performance of named query registry

  • Loading branch information...
commit 7d99ca57f3da15a8843332e52e295bf7ea94254b 1 parent dc193c3
@sebersole sebersole authored
View
19 hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java
@@ -251,4 +251,23 @@ public Integer getMaxResults() {
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()
+ );
+ }
}
View
23 hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java
@@ -216,4 +216,27 @@ public boolean isCallable() {
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()
+ );
+ }
}
View
8 hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java
@@ -48,6 +48,7 @@
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 CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy();
public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver();
+
+ /**
+ * Provides access to the named query repository
+ *
+ * @return
+ */
+ public NamedQueryRepository getNamedQueryRepository();
}
View
185 hibernate-core/src/main/java/org/hibernate/internal/NamedQueryRepository.java
@@ -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;
+ }
+}
View
137 hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java
@@ -191,9 +191,7 @@
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 void sessionFactoryClosed(SessionFactory factory) {
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 void sessionFactoryClosed(SessionFactory factory) {
}
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 QueryPlanCache getQueryPlanCache() {
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 Reference getReference() {
);
}
+ @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 {
View
6 hibernate-core/src/main/java/org/hibernate/internal/util/collections/CollectionHelper.java
@@ -146,4 +146,10 @@ public static boolean isNotEmpty(Collection collection) {
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;
+ }
}

0 comments on commit 7d99ca5

Please sign in to comment.
Something went wrong with that request. Please try again.