HHH-3383 - QueryKey is storing references to entities instead of identifiers

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@16656 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2009-06-01 21:12:25 +00:00
parent aa710c6668
commit 9c26388abf
2 changed files with 92 additions and 61 deletions

View File

@ -20,7 +20,6 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.cache; package org.hibernate.cache;
@ -41,20 +40,24 @@ import org.hibernate.util.EqualsHelper;
import org.hibernate.util.CollectionHelper; import org.hibernate.util.CollectionHelper;
/** /**
* A key that identifies a particular query with bound parameter values * A key that identifies a particular query with bound parameter values. This is the object Hibernate uses
* as its key into its query cache.
*
* @author Gavin King * @author Gavin King
* @author Steve Ebersole
*/ */
public class QueryKey implements Serializable { public class QueryKey implements Serializable {
private final String sqlQueryString; private final String sqlQueryString;
private final Type[] types; private final Type[] positionalParameterTypes;
private final Object[] values; private final Object[] positionalParameterValues;
private final Map namedParameters;
private final Integer firstRow; private final Integer firstRow;
private final Integer maxRows; private final Integer maxRows;
private final Map namedParameters;
private final EntityMode entityMode; private final EntityMode entityMode;
private final Set filters; private final Set filterKeys;
// the user provided resulttransformer, not the one used with "select new". Here to avoid mangling transformed/non-transformed results. // the user provided resulttransformer, not the one used with "select new". Here to avoid mangling
// transformed/non-transformed results.
private final ResultTransformer customTransformer; private final ResultTransformer customTransformer;
/** /**
@ -63,10 +66,20 @@ public class QueryKey implements Serializable {
*/ */
private transient int hashCode; private transient int hashCode;
/**
* Generates a QueryKey.
*
* @param queryString The sql query string.
* @param queryParameters The query parameters
* @param filterKeys The keys of any enabled filters.
* @param session The current session.
*
* @return The generate query cache key.
*/
public static QueryKey generateQueryKey( public static QueryKey generateQueryKey(
String queryString, String queryString,
QueryParameters queryParameters, QueryParameters queryParameters,
Set filters, Set filterKeys,
SessionImplementor session) { SessionImplementor session) {
// disassemble positional parameters // disassemble positional parameters
final int positionalParameterCount = queryParameters.getPositionalParameterTypes().length; final int positionalParameterCount = queryParameters.getPositionalParameterTypes().length;
@ -113,54 +126,55 @@ public class QueryKey implements Serializable {
namedParameters, namedParameters,
firstRow, firstRow,
maxRows, maxRows,
filters, filterKeys,
session.getEntityMode(), session.getEntityMode(),
queryParameters.getResultTransformer() queryParameters.getResultTransformer()
); );
} }
/*package*/ QueryKey( /**
* Package-protected constructor.
*
* @param sqlQueryString The sql query string.
* @param positionalParameterTypes Positional parameter types.
* @param positionalParameterValues Positional parameter values.
* @param namedParameters Named parameters.
* @param firstRow First row selection, if any.
* @param maxRows Max-rows selection, if any.
* @param filterKeys Enabled filter keys, if any.
* @param entityMode The entity mode.
* @param customTransformer Custom result transformer, if one.
*/
QueryKey(
String sqlQueryString, String sqlQueryString,
Type[] types, Type[] positionalParameterTypes,
Object[] values, Object[] positionalParameterValues,
Map namedParameters, Map namedParameters,
Integer firstRow, Integer firstRow,
Integer maxRows, Integer maxRows,
Set filters, Set filterKeys,
EntityMode entityMode, EntityMode entityMode,
ResultTransformer customTransformer) { ResultTransformer customTransformer) {
this.sqlQueryString = sqlQueryString; this.sqlQueryString = sqlQueryString;
this.types = types; this.positionalParameterTypes = positionalParameterTypes;
this.values = values; this.positionalParameterValues = positionalParameterValues;
this.namedParameters = namedParameters; this.namedParameters = namedParameters;
this.firstRow = firstRow; this.firstRow = firstRow;
this.maxRows = maxRows; this.maxRows = maxRows;
this.entityMode = entityMode; this.entityMode = entityMode;
this.filters = filters; this.filterKeys = filterKeys;
this.customTransformer = customTransformer; this.customTransformer = customTransformer;
this.hashCode = generateHashCode(); this.hashCode = generateHashCode();
} }
// public QueryKey(String queryString, QueryParameters queryParameters, Set filters, EntityMode entityMode) { /**
// this.sqlQueryString = queryString; * Deserialization hook used to re-init the cached hashcode which is needed for proper clustering support.
// this.types = queryParameters.getPositionalParameterTypes(); *
// this.values = queryParameters.getPositionalParameterValues(); * @param in The object input stream.
// RowSelection selection = queryParameters.getRowSelection(); *
// if (selection!=null) { * @throws IOException Thrown by normal deserialization
// firstRow = selection.getFirstRow(); * @throws ClassNotFoundException Thrown by normal deserialization
// maxRows = selection.getMaxRows(); */
// }
// else {
// firstRow = null;
// maxRows = null;
// }
// this.namedParameters = queryParameters.getNamedParameters();
// this.entityMode = entityMode;
// this.filters = filters;
// this.customTransformer = queryParameters.getResultTransformer();
// this.hashCode = generateHashCode();
// }
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); in.defaultReadObject();
this.hashCode = generateHashCode(); this.hashCode = generateHashCode();
@ -170,16 +184,19 @@ public class QueryKey implements Serializable {
int result = 13; int result = 13;
result = 37 * result + ( firstRow==null ? 0 : firstRow.hashCode() ); result = 37 * result + ( firstRow==null ? 0 : firstRow.hashCode() );
result = 37 * result + ( maxRows==null ? 0 : maxRows.hashCode() ); result = 37 * result + ( maxRows==null ? 0 : maxRows.hashCode() );
for ( int i=0; i<values.length; i++ ) { for ( int i=0; i< positionalParameterValues.length; i++ ) {
result = 37 * result + ( values[i]==null ? 0 : types[i].getHashCode( values[i], entityMode ) ); result = 37 * result + ( positionalParameterValues[i]==null ? 0 : positionalParameterTypes[i].getHashCode( positionalParameterValues[i], entityMode ) );
} }
result = 37 * result + ( namedParameters==null ? 0 : namedParameters.hashCode() ); result = 37 * result + ( namedParameters==null ? 0 : namedParameters.hashCode() );
result = 37 * result + ( filters==null ? 0 : filters.hashCode() ); result = 37 * result + ( filterKeys ==null ? 0 : filterKeys.hashCode() );
result = 37 * result + ( customTransformer==null ? 0 : customTransformer.hashCode() ); result = 37 * result + ( customTransformer==null ? 0 : customTransformer.hashCode() );
result = 37 * result + sqlQueryString.hashCode(); result = 37 * result + sqlQueryString.hashCode();
return result; return result;
} }
/**
* {@inheritDoc}
*/
public boolean equals(Object other) { public boolean equals(Object other) {
if ( !( other instanceof QueryKey ) ) { if ( !( other instanceof QueryKey ) ) {
return false; return false;
@ -194,54 +211,57 @@ public class QueryKey implements Serializable {
if ( !EqualsHelper.equals( customTransformer, that.customTransformer ) ) { if ( !EqualsHelper.equals( customTransformer, that.customTransformer ) ) {
return false; return false;
} }
if ( types == null ) { if ( positionalParameterTypes == null ) {
if ( that.types != null ) { if ( that.positionalParameterTypes != null ) {
return false; return false;
} }
} }
else { else {
if ( that.types == null ) { if ( that.positionalParameterTypes == null ) {
return false; return false;
} }
if ( types.length != that.types.length ) { if ( positionalParameterTypes.length != that.positionalParameterTypes.length ) {
return false; return false;
} }
for ( int i = 0; i < types.length; i++ ) { for ( int i = 0; i < positionalParameterTypes.length; i++ ) {
if ( types[i].getReturnedClass() != that.types[i].getReturnedClass() ) { if ( positionalParameterTypes[i].getReturnedClass() != that.positionalParameterTypes[i].getReturnedClass() ) {
return false; return false;
} }
if ( !types[i].isEqual( values[i], that.values[i], entityMode ) ) { if ( !positionalParameterTypes[i].isEqual( positionalParameterValues[i], that.positionalParameterValues[i], entityMode ) ) {
return false; return false;
} }
} }
} }
return EqualsHelper.equals( filters, that.filters ) return EqualsHelper.equals( filterKeys, that.filterKeys )
&& EqualsHelper.equals( namedParameters, that.namedParameters ); && EqualsHelper.equals( namedParameters, that.namedParameters );
} }
/**
* {@inheritDoc}
*/
public int hashCode() { public int hashCode() {
return hashCode; return hashCode;
} }
/**
* {@inheritDoc}
*/
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer() StringBuffer buf = new StringBuffer()
.append( "sql: " ) .append( "sql: " )
.append( sqlQueryString ); .append( sqlQueryString );
if ( values != null ) { if ( positionalParameterValues != null ) {
buf.append( "; parameters: " ); buf.append( "; parameters: " );
for ( int i = 0; i < values.length; i++ ) { for ( int i = 0; i < positionalParameterValues.length; i++ ) {
buf.append( values[i] ) buf.append( positionalParameterValues[i] ).append( ", " );
.append( ", " );
} }
} }
if ( namedParameters != null ) { if ( namedParameters != null ) {
buf.append( "; named parameters: " ) buf.append( "; named parameters: " ).append( namedParameters );
.append( namedParameters );
} }
if ( filters != null ) { if ( filterKeys != null ) {
buf.append( "; filters: " ) buf.append( "; filterKeys: " ).append( filterKeys );
.append( filters );
} }
if ( firstRow != null ) { if ( firstRow != null ) {
buf.append( "; first row: " ).append( firstRow ); buf.append( "; first row: " ).append( firstRow );

View File

@ -20,7 +20,6 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.util; package org.hibernate.util;
@ -32,16 +31,28 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Various help for handling collections.
*
* @author Gavin King * @author Gavin King
* @author Steve Ebersole
*/ */
public final class CollectionHelper { public final class CollectionHelper {
public static final List EMPTY_LIST = Collections.unmodifiableList( new ArrayList(0) ); 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 Collection EMPTY_COLLECTION = Collections.unmodifiableCollection( new ArrayList(0) );
public static final Map EMPTY_MAP = Collections.unmodifiableMap( new HashMap(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) { public static Map mapOfSize(int size) {
final int currentSize = (int) (size / 0.75f); final int currentSize = (int) (size / 0.75f);
return new HashMap( Math.max( currentSize+ 1, 16), 0.75f ); return new HashMap( Math.max( currentSize+ 1, 16), 0.75f );