Author: steve.ebersole(a)jboss.com
Date: 2009-06-01 16:36:35 -0400 (Mon, 01 Jun 2009)
New Revision: 16653
Modified:
core/branches/Branch_3_2/src/org/hibernate/cache/QueryKey.java
core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java
core/branches/Branch_3_2/src/org/hibernate/util/CollectionHelper.java
Log:
HHH-3383 - QueryKey is storing references to entities instead of identifiers
Modified: core/branches/Branch_3_2/src/org/hibernate/cache/QueryKey.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/cache/QueryKey.java 2009-06-01 18:54:44 UTC
(rev 16652)
+++ core/branches/Branch_3_2/src/org/hibernate/cache/QueryKey.java 2009-06-01 20:36:35 UTC
(rev 16653)
@@ -1,19 +1,47 @@
-//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.cache;
import java.io.Serializable;
+import java.io.IOException;
import java.util.Map;
import java.util.Set;
+import java.util.Iterator;
import org.hibernate.EntityMode;
import org.hibernate.engine.QueryParameters;
import org.hibernate.engine.RowSelection;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.TypedValue;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
import org.hibernate.util.EqualsHelper;
+import org.hibernate.util.CollectionHelper;
/**
* A key that identifies a particular query with bound parameter values
+ *
* @author Gavin King
*/
public class QueryKey implements Serializable {
@@ -25,17 +53,51 @@
private final Map namedParameters;
private final EntityMode entityMode;
private final Set filters;
- private final int hashCode;
-
+
// the user provided resulttransformer, not the one used with "select new".
Here to avoid mangling transformed/non-transformed results.
private final ResultTransformer customTransformer;
-
- public QueryKey(String queryString, QueryParameters queryParameters, Set filters,
EntityMode entityMode) {
- this.sqlQueryString = queryString;
- this.types = queryParameters.getPositionalParameterTypes();
- this.values = queryParameters.getPositionalParameterValues();
- RowSelection selection = queryParameters.getRowSelection();
- if (selection!=null) {
+
+ /**
+ * For performance reasons, the hashCode is cached; however, it is marked transient so
that it can be
+ * recalculated as part of the serialization process which allows distributed query
caches to work properly.
+ */
+ private transient int hashCode;
+
+ public static QueryKey generateQueryKey(
+ String queryString,
+ QueryParameters queryParameters,
+ Set filters,
+ SessionImplementor session) {
+ // disassemble positional parameters
+ final int positionalParameterCount =
queryParameters.getPositionalParameterTypes().length;
+ final Type[] types = new Type[positionalParameterCount];
+ final Object[] values = new Object[positionalParameterCount];
+ for ( int i = 0; i < positionalParameterCount; i++ ) {
+ types[i] = queryParameters.getPositionalParameterTypes()[i];
+ values[i] = types[i].disassemble( queryParameters.getPositionalParameterValues()[i],
session, null );
+ }
+
+ // disassemble named parameters
+ Map namedParameters = CollectionHelper.mapOfSize(
queryParameters.getNamedParameters().size() );
+ Iterator itr = queryParameters.getNamedParameters().entrySet().iterator();
+ while ( itr.hasNext() ) {
+ final Map.Entry namedParameterEntry = ( Map.Entry ) itr.next();
+ final TypedValue original = ( TypedValue ) namedParameterEntry.getValue();
+ namedParameters.put(
+ namedParameterEntry.getKey(),
+ new TypedValue(
+ original.getType(),
+ original.getType().disassemble( original.getValue(), session, null ),
+ session.getEntityMode()
+ )
+ );
+ }
+
+ // decode row selection...
+ final RowSelection selection = queryParameters.getRowSelection();
+ final Integer firstRow;
+ final Integer maxRows;
+ if ( selection != null ) {
firstRow = selection.getFirstRow();
maxRows = selection.getMaxRows();
}
@@ -43,40 +105,48 @@
firstRow = null;
maxRows = null;
}
- this.namedParameters = queryParameters.getNamedParameters();
+
+ return new QueryKey(
+ queryString,
+ types,
+ values,
+ namedParameters,
+ firstRow,
+ maxRows,
+ filters,
+ session.getEntityMode(),
+ queryParameters.getResultTransformer()
+ );
+ }
+
+ /*package*/ QueryKey(
+ String sqlQueryString,
+ Type[] types,
+ Object[] values,
+ Map namedParameters,
+ Integer firstRow,
+ Integer maxRows,
+ Set filters,
+ EntityMode entityMode,
+ ResultTransformer customTransformer) {
+ this.sqlQueryString = sqlQueryString;
+ this.types = types;
+ this.values = values;
+ this.namedParameters = namedParameters;
+ this.firstRow = firstRow;
+ this.maxRows = maxRows;
this.entityMode = entityMode;
this.filters = filters;
- this.customTransformer = queryParameters.getResultTransformer();
- this.hashCode = getHashCode();
+ this.customTransformer = customTransformer;
+ this.hashCode = generateHashCode();
}
-
- public boolean equals(Object other) {
- if ( !( other instanceof QueryKey ) ) return false;
- QueryKey that = (QueryKey) other;
- if ( !sqlQueryString.equals(that.sqlQueryString) ) return false;
- if ( !EqualsHelper.equals(firstRow, that.firstRow) || !EqualsHelper.equals(maxRows,
that.maxRows) ) return false;
- if ( !EqualsHelper.equals(customTransformer, that.customTransformer) ) return false;
- if (types==null) {
- if (that.types!=null) return false;
- }
- else {
- if (that.types==null) return false;
- if ( types.length!=that.types.length ) return false;
- for ( int i=0; i<types.length; i++ ) {
- if ( types[i].getReturnedClass() != that.types[i].getReturnedClass() ) return false;
- if ( !types[i].isEqual( values[i], that.values[i], entityMode ) ) return false;
- }
- }
- if ( !EqualsHelper.equals(filters, that.filters) ) return false;
- if ( !EqualsHelper.equals(namedParameters, that.namedParameters) ) return false;
- return true;
+
+ private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
+ in.defaultReadObject();
+ this.hashCode = generateHashCode();
}
-
- public int hashCode() {
- return hashCode;
- }
-
- private int getHashCode() {
+
+ private int generateHashCode() {
int result = 13;
result = 37 * result + ( firstRow==null ? 0 : firstRow.hashCode() );
result = 37 * result + ( maxRows==null ? 0 : maxRows.hashCode() );
@@ -90,29 +160,79 @@
return result;
}
+ public boolean equals(Object other) {
+ if ( !( other instanceof QueryKey ) ) {
+ return false;
+ }
+ QueryKey that = ( QueryKey ) other;
+ if ( !sqlQueryString.equals( that.sqlQueryString ) ) {
+ return false;
+ }
+ if ( !EqualsHelper.equals( firstRow, that.firstRow ) || !EqualsHelper.equals( maxRows,
that.maxRows ) ) {
+ return false;
+ }
+ if ( !EqualsHelper.equals( customTransformer, that.customTransformer ) ) {
+ return false;
+ }
+ if ( types == null ) {
+ if ( that.types != null ) {
+ return false;
+ }
+ }
+ else {
+ if ( that.types == null ) {
+ return false;
+ }
+ if ( types.length != that.types.length ) {
+ return false;
+ }
+ for ( int i = 0; i < types.length; i++ ) {
+ if ( types[i].getReturnedClass() != that.types[i].getReturnedClass() ) {
+ return false;
+ }
+ if ( !types[i].isEqual( values[i], that.values[i], entityMode ) ) {
+ return false;
+ }
+ }
+ }
+
+ return EqualsHelper.equals( filters, that.filters )
+ && EqualsHelper.equals( namedParameters, that.namedParameters );
+ }
+
+ public int hashCode() {
+ return hashCode;
+ }
+
public String toString() {
StringBuffer buf = new StringBuffer()
- .append("sql: ")
- .append(sqlQueryString);
- if (values!=null) {
- buf.append("; parameters: ");
- for (int i=0; i<values.length; i++) {
+ .append( "sql: " )
+ .append( sqlQueryString );
+ if ( values != null ) {
+ buf.append( "; parameters: " );
+ for ( int i = 0; i < values.length; i++ ) {
buf.append( values[i] )
- .append(", ");
+ .append( ", " );
}
}
- if (namedParameters!=null) {
- buf.append("; named parameters: ")
- .append(namedParameters);
+ if ( namedParameters != null ) {
+ buf.append( "; named parameters: " )
+ .append( namedParameters );
}
- if (filters!=null) {
- buf.append("; filters: ")
- .append(filters);
+ if ( filters != null ) {
+ buf.append( "; filters: " )
+ .append( filters );
}
- if (firstRow!=null) buf.append("; first row: ").append(firstRow);
- if (maxRows!=null) buf.append("; max rows: ").append(maxRows);
- if (customTransformer!=null) buf.append("; transformer:
").append(customTransformer);
+ if ( firstRow != null ) {
+ buf.append( "; first row: " ).append( firstRow );
+ }
+ if ( maxRows != null ) {
+ buf.append( "; max rows: " ).append( maxRows );
+ }
+ if ( customTransformer != null ) {
+ buf.append( "; transformer: " ).append( customTransformer );
+ }
return buf.toString();
}
-
+
}
Modified: core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java 2009-06-01 18:54:44 UTC
(rev 16652)
+++ core/branches/Branch_3_2/src/org/hibernate/loader/Loader.java 2009-06-01 20:36:35 UTC
(rev 16653)
@@ -2117,15 +2117,15 @@
QueryCache queryCache = factory.getQueryCache( queryParameters.getCacheRegion() );
Set filterKeys = FilterKey.createFilterKeys(
- session.getEnabledFilters(),
+ session.getEnabledFilters(),
session.getEntityMode()
- );
- QueryKey key = new QueryKey(
+ );
+ QueryKey key = QueryKey.generateQueryKey(
getSQLString(),
queryParameters,
filterKeys,
- session.getEntityMode()
- );
+ session
+ );
List result = getResultFromQueryCache(
session,
@@ -2134,7 +2134,7 @@
resultTypes,
queryCache,
key
- );
+ );
if ( result == null ) {
result = doList( session, queryParameters );
@@ -2146,7 +2146,7 @@
queryCache,
key,
result
- );
+ );
}
return getResultList( result, queryParameters.getResultTransformer() );
Modified: core/branches/Branch_3_2/src/org/hibernate/util/CollectionHelper.java
===================================================================
--- core/branches/Branch_3_2/src/org/hibernate/util/CollectionHelper.java 2009-06-01
18:54:44 UTC (rev 16652)
+++ core/branches/Branch_3_2/src/org/hibernate/util/CollectionHelper.java 2009-06-01
20:36:35 UTC (rev 16653)
@@ -1,4 +1,26 @@
-//$Id$
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
+ *
+ * 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.util;
import java.util.ArrayList;
@@ -9,14 +31,30 @@
import java.util.Map;
/**
+ * Various help for handling collections.
+ *
* @author Gavin King
+ * @author Steve Ebersole
*/
public final class CollectionHelper {
public static final List EMPTY_LIST = Collections.unmodifiableList( new ArrayList(0) );
public static final Collection EMPTY_COLLECTION = Collections.unmodifiableCollection(
new ArrayList(0) );
public static final Map EMPTY_MAP = Collections.unmodifiableMap( new HashMap(0) );
-
- private CollectionHelper() {}
+ private CollectionHelper() {
+ }
+
+ /**
+ * Build a properly sized map, especially handling load size and load factor to prevent
immediate resizing.
+ * <p/>
+ * Especially helpful for copy map contents.
+ *
+ * @param size The size to make the map.
+ * @return The sized map.
+ */
+ public static Map mapOfSize(int size) {
+ final int currentSize = (int) (size / 0.75f);
+ return new HashMap( Math.max( currentSize+ 1, 16), 0.75f );
+ }
}