[hibernate-commits] Hibernate SVN: r16654 - in core/branches/Branch_3_3/core/src: main/java/org/hibernate/loader and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Jun 1 17:11:43 EDT 2009


Author: steve.ebersole at jboss.com
Date: 2009-06-01 17:11:43 -0400 (Mon, 01 Jun 2009)
New Revision: 16654

Modified:
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/cache/QueryKey.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/loader/Loader.java
   core/branches/Branch_3_3/core/src/main/java/org/hibernate/util/CollectionHelper.java
   core/branches/Branch_3_3/core/src/test/java/org/hibernate/cache/QueryKeyTest.java
Log:
HHH-3383 - QueryKey is storing references to entities instead of identifiers


Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/cache/QueryKey.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/cache/QueryKey.java	2009-06-01 20:36:35 UTC (rev 16653)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/cache/QueryKey.java	2009-06-01 21:11:43 UTC (rev 16654)
@@ -20,7 +20,6 @@
  * Free Software Foundation, Inc.
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
- *
  */
 package org.hibernate.cache;
 
@@ -28,29 +27,37 @@
 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
+ * 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 Steve Ebersole
  */
 public class QueryKey implements Serializable {
 	private final String sqlQueryString;
-	private final Type[] types;
-	private final Object[] values;
+	private final Type[] positionalParameterTypes;
+	private final Object[] positionalParameterValues;
+	private final Map namedParameters;
 	private final Integer firstRow;
 	private final Integer maxRows;
-	private final Map namedParameters;
 	private final EntityMode entityMode;
-	private final Set filters;
-	
-	// the user provided resulttransformer, not the one used with "select new". Here to avoid mangling transformed/non-transformed results.
+	private final Set filterKeys;
+
+	// the user provided resulttransformer, not the one used with "select new". Here to avoid mangling
+	// transformed/non-transformed results.
 	private final ResultTransformer customTransformer;
 
 	/**
@@ -58,13 +65,52 @@
 	 * recalculated as part of the serialization process which allows distributed query caches to work properly.
 	 */
 	private transient int hashCode;
-	
-	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) {
+
+	/**
+	 * 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(
+			String queryString,
+			QueryParameters queryParameters,
+			Set filterKeys,
+			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();
 		}
@@ -72,13 +118,63 @@
 			firstRow = null;
 			maxRows = null;
 		}
-		this.namedParameters = queryParameters.getNamedParameters();
+
+		return new QueryKey(
+				queryString,
+				types,
+				values,
+				namedParameters,
+				firstRow,
+				maxRows,
+				filterKeys,
+				session.getEntityMode(),
+				queryParameters.getResultTransformer()
+		);
+	}
+
+	/**
+	 * 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,
+			Type[] positionalParameterTypes,
+			Object[] positionalParameterValues,
+			Map namedParameters,
+			Integer firstRow,
+			Integer maxRows,
+			Set filterKeys,
+			EntityMode entityMode,
+			ResultTransformer customTransformer) {
+		this.sqlQueryString = sqlQueryString;
+		this.positionalParameterTypes = positionalParameterTypes;
+		this.positionalParameterValues = positionalParameterValues;
+		this.namedParameters = namedParameters;
+		this.firstRow = firstRow;
+		this.maxRows = maxRows;
 		this.entityMode = entityMode;
-		this.filters = filters;
-		this.customTransformer = queryParameters.getResultTransformer();
+		this.filterKeys = filterKeys;
+		this.customTransformer = customTransformer;
 		this.hashCode = generateHashCode();
 	}
 
+	/**
+	 * Deserialization hook used to re-init the cached hashcode which is needed for proper clustering support.
+	 *
+	 * @param in The object input stream.
+	 *
+	 * @throws IOException Thrown by normal deserialization
+	 * @throws ClassNotFoundException Thrown by normal deserialization
+	 */
 	private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
 		in.defaultReadObject();
 		this.hashCode = generateHashCode();
@@ -88,65 +184,95 @@
 		int result = 13;
 		result = 37 * result + ( firstRow==null ? 0 : firstRow.hashCode() );
 		result = 37 * result + ( maxRows==null ? 0 : maxRows.hashCode() );
-		for ( int i=0; i<values.length; i++ ) {
-			result = 37 * result + ( values[i]==null ? 0 : types[i].getHashCode( values[i], entityMode ) );
+		for ( int i=0; i< positionalParameterValues.length; i++ ) {
+			result = 37 * result + ( positionalParameterValues[i]==null ? 0 : positionalParameterTypes[i].getHashCode( positionalParameterValues[i], entityMode ) );
 		}
 		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 + sqlQueryString.hashCode();
 		return result;
 	}
 
-	public int hashCode() {
-		return hashCode;
-	}
-	
+	/**
+	 * {@inheritDoc}
+	 */
 	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;
+		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 ( positionalParameterTypes == null ) {
+			if ( that.positionalParameterTypes != 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 ( that.positionalParameterTypes == null ) {
+				return false;
 			}
+			if ( positionalParameterTypes.length != that.positionalParameterTypes.length ) {
+				return false;
+			}
+			for ( int i = 0; i < positionalParameterTypes.length; i++ ) {
+				if ( positionalParameterTypes[i].getReturnedClass() != that.positionalParameterTypes[i].getReturnedClass() ) {
+					return false;
+				}
+				if ( !positionalParameterTypes[i].isEqual( positionalParameterValues[i], that.positionalParameterValues[i], entityMode ) ) {
+					return false;
+				}
+			}
 		}
-		if ( !EqualsHelper.equals(filters, that.filters) ) return false;
-		if ( !EqualsHelper.equals(namedParameters, that.namedParameters) ) return false;
-		return true;
+
+		return EqualsHelper.equals( filterKeys, that.filterKeys )
+				&& EqualsHelper.equals( namedParameters, that.namedParameters );
 	}
 
+	/**
+	 * {@inheritDoc}
+	 */
+	public int hashCode() {
+		return hashCode;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
 	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++) {
-				buf.append( values[i] )
-					.append(", ");
+				.append( "sql: " )
+				.append( sqlQueryString );
+		if ( positionalParameterValues != null ) {
+			buf.append( "; parameters: " );
+			for ( int i = 0; i < positionalParameterValues.length; i++ ) {
+				buf.append( positionalParameterValues[i] ).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 ( filterKeys != null ) {
+			buf.append( "; filterKeys: " ).append( filterKeys );
 		}
-		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_3/core/src/main/java/org/hibernate/loader/Loader.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/loader/Loader.java	2009-06-01 20:36:35 UTC (rev 16653)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/loader/Loader.java	2009-06-01 21:11:43 UTC (rev 16654)
@@ -2138,15 +2138,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, 
@@ -2155,7 +2155,7 @@
 				resultTypes, 
 				queryCache, 
 				key 
-			);
+		);
 
 		if ( result == null ) {
 			result = doList( session, queryParameters );
@@ -2167,7 +2167,7 @@
 					queryCache, 
 					key, 
 					result 
-				);
+			);
 		}
 
 		return getResultList( result, queryParameters.getResultTransformer() );

Modified: core/branches/Branch_3_3/core/src/main/java/org/hibernate/util/CollectionHelper.java
===================================================================
--- core/branches/Branch_3_3/core/src/main/java/org/hibernate/util/CollectionHelper.java	2009-06-01 20:36:35 UTC (rev 16653)
+++ core/branches/Branch_3_3/core/src/main/java/org/hibernate/util/CollectionHelper.java	2009-06-01 21:11:43 UTC (rev 16654)
@@ -20,7 +20,6 @@
  * Free Software Foundation, Inc.
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
- *
  */
 package org.hibernate.util;
 
@@ -32,7 +31,10 @@
 import java.util.Map;
 
 /**
+ * Various help for handling collections.
+ *
  * @author Gavin King
+ * @author Steve Ebersole
  */
 public final class CollectionHelper {
 
@@ -40,6 +42,19 @@
 	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 );
+	}
 }

Modified: core/branches/Branch_3_3/core/src/test/java/org/hibernate/cache/QueryKeyTest.java
===================================================================
--- core/branches/Branch_3_3/core/src/test/java/org/hibernate/cache/QueryKeyTest.java	2009-06-01 20:36:35 UTC (rev 16653)
+++ core/branches/Branch_3_3/core/src/test/java/org/hibernate/cache/QueryKeyTest.java	2009-06-01 21:11:43 UTC (rev 16654)
@@ -20,7 +20,6 @@
  * Free Software Foundation, Inc.
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
- *
  */
 package org.hibernate.cache;
 
@@ -29,7 +28,6 @@
 
 import junit.framework.TestCase;
 
-import org.hibernate.engine.QueryParameters;
 import org.hibernate.EntityMode;
 import org.hibernate.transform.RootEntityResultTransformer;
 import org.hibernate.transform.ResultTransformer;
@@ -49,35 +47,31 @@
 	private static final String QUERY_STRING = "the query string";
 
 	public void testSerializedEquality() {
-		doTest( buildBasicKey( new QueryParameters() ) );
+		doTest( buildBasicKey( null ) );
 	}
 
 	public void testSerializedEqualityWithResultTransformer() {
-		doTest( buildBasicKey( buildQueryParameters( RootEntityResultTransformer.INSTANCE ) ) );
-		doTest( buildBasicKey( buildQueryParameters( DistinctRootEntityResultTransformer.INSTANCE ) ) );
-		doTest( buildBasicKey( buildQueryParameters( DistinctResultTransformer.INSTANCE ) ) );
-		doTest( buildBasicKey( buildQueryParameters( AliasToEntityMapResultTransformer.INSTANCE ) ) );
-		doTest( buildBasicKey( buildQueryParameters( PassThroughResultTransformer.INSTANCE ) ) );
+		doTest( buildBasicKey( RootEntityResultTransformer.INSTANCE ) );
+		doTest( buildBasicKey( DistinctRootEntityResultTransformer.INSTANCE ) );
+		doTest( buildBasicKey( DistinctResultTransformer.INSTANCE ) );
+		doTest( buildBasicKey( AliasToEntityMapResultTransformer.INSTANCE ) );
+		doTest( buildBasicKey( PassThroughResultTransformer.INSTANCE ) );
 	}
 
-	private QueryParameters buildQueryParameters(ResultTransformer resultTransformer) {
-		return new QueryParameters(
-				ArrayHelper.EMPTY_TYPE_ARRAY, 		// param types
-				ArrayHelper.EMPTY_OBJECT_ARRAY,		// param values
-				Collections.EMPTY_MAP,				// lock modes
-				null,								// row selection
-				false,								// cacheable?
-				"",									// cache region
-				"", 								// SQL comment
-				false,								// is natural key lookup?
-				resultTransformer					// the result transformer, duh! ;)
+	private QueryKey buildBasicKey(ResultTransformer resultTransformer) {
+		return new QueryKey(
+				QUERY_STRING,
+				ArrayHelper.EMPTY_TYPE_ARRAY, 		// positional param types
+				ArrayHelper.EMPTY_OBJECT_ARRAY,		// positional param values
+				Collections.EMPTY_MAP,				// named params
+				null,								// firstRow selection
+				null,								// maxRows selection
+				Collections.EMPTY_SET, 				// filter keys
+				EntityMode.POJO,					// entity mode
+				resultTransformer					// the result transformer
 		);
 	}
 
-	private QueryKey buildBasicKey(QueryParameters queryParameters) {
-		return new QueryKey( QUERY_STRING, queryParameters, Collections.EMPTY_SET, EntityMode.POJO );
-	}
-
 	private void doTest(QueryKey key) {
 		HashMap map = new HashMap();
 




More information about the hibernate-commits mailing list