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:
parent
aa710c6668
commit
9c26388abf
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
Loading…
Reference in New Issue