Permalink
Browse files

HHH-7402 - Improve performance of named query registry

  • Loading branch information...
1 parent dc193c3 commit 7d99ca57f3da15a8843332e52e295bf7ea94254b @sebersole sebersole committed Mar 26, 2013
@@ -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()
+ );
+ }
}
@@ -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()
+ );
+ }
}
@@ -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();
}
@@ -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;
+ }
+}
Oops, something went wrong.

0 comments on commit 7d99ca5

Please sign in to comment.