HHH-6974 - Add caching to new "load access" api for natural id loading

This commit is contained in:
Steve Ebersole 2012-02-08 09:08:11 -06:00
parent 368c4cc2bc
commit 199d08210d
6 changed files with 165 additions and 136 deletions

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008-2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,18 +20,14 @@
* 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.criterion; package org.hibernate.criterion;
/** /**
* @author Gavin King * @author Gavin King
*/ */
public class Conjunction extends Junction { public class Conjunction extends Junction {
public Conjunction() { public Conjunction() {
super("and"); super( Nature.AND );
} }
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008-2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,18 +20,14 @@
* 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.criterion; package org.hibernate.criterion;
/** /**
* @author Gavin King * @author Gavin King
*/ */
public class Disjunction extends Junction { public class Disjunction extends Junction {
protected Disjunction() { protected Disjunction() {
super("or"); super( Nature.OR );
} }
} }

View File

@ -24,6 +24,7 @@
*/ */
package org.hibernate.criterion; package org.hibernate.criterion;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -39,56 +40,65 @@
* @author Gavin King * @author Gavin King
*/ */
public class Junction implements Criterion { public class Junction implements Criterion {
private final Nature nature;
private final List<Criterion> conditions = new ArrayList<Criterion>();
private final List criteria = new ArrayList(); protected Junction(Nature nature) {
private final String op; this.nature = nature;
protected Junction(String op) {
this.op = op;
} }
public Junction add(Criterion criterion) { public Junction add(Criterion criterion) {
criteria.add(criterion); conditions.add( criterion );
return this; return this;
} }
public String getOp() { public Nature getNature() {
return op; return nature;
} }
public TypedValue[] getTypedValues(Criteria crit, CriteriaQuery criteriaQuery) public Iterable<Criterion> conditions() {
throws HibernateException { return conditions;
ArrayList typedValues = new ArrayList(); }
Iterator iter = criteria.iterator();
while ( iter.hasNext() ) { @Override
TypedValue[] subvalues = ( (Criterion) iter.next() ).getTypedValues(crit, criteriaQuery); public TypedValue[] getTypedValues(Criteria crit, CriteriaQuery criteriaQuery) throws HibernateException {
for ( int i=0; i<subvalues.length; i++ ) { ArrayList<TypedValue> typedValues = new ArrayList<TypedValue>();
typedValues.add( subvalues[i] ); for ( Criterion condition : conditions ) {
} TypedValue[] subValues = condition.getTypedValues( crit, criteriaQuery );
Collections.addAll( typedValues, subValues );
} }
return (TypedValue[]) typedValues.toArray( new TypedValue[ typedValues.size() ] ); return typedValues.toArray( new TypedValue[ typedValues.size() ] );
} }
public String toSqlString(Criteria crit, CriteriaQuery criteriaQuery) @Override
throws HibernateException { public String toSqlString(Criteria crit, CriteriaQuery criteriaQuery) throws HibernateException {
if ( conditions.size()==0 ) {
return "1=1";
}
if ( criteria.size()==0 ) return "1=1"; StringBuilder buffer = new StringBuilder().append( '(' );
Iterator itr = conditions.iterator();
StringBuffer buffer = new StringBuffer() while ( itr.hasNext() ) {
.append('('); buffer.append( ( (Criterion) itr.next() ).toSqlString( crit, criteriaQuery ) );
Iterator iter = criteria.iterator(); if ( itr.hasNext() ) {
while ( iter.hasNext() ) { buffer.append(' ').append( nature.getOperator() ).append(' ');
buffer.append( ( (Criterion) iter.next() ).toSqlString(crit, criteriaQuery) ); }
if ( iter.hasNext() ) buffer.append(' ').append(op).append(' ');
} }
return buffer.append(')').toString(); return buffer.append(')').toString();
} }
/** @Override
* @see java.lang.Object#toString()
*/
public String toString() { public String toString() {
return '(' + StringHelper.join( ' ' + op + ' ', criteria.iterator() ) + ')'; return '(' + StringHelper.join( ' ' + nature.getOperator() + ' ', conditions.iterator() ) + ')';
} }
public static enum Nature {
AND,
OR
;
public String getOperator() {
return name().toLowerCase();
}
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,11 +20,11 @@
* 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.criterion; package org.hibernate.criterion;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.Criteria; import org.hibernate.Criteria;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -39,25 +39,34 @@
* @see Session#bySimpleNaturalId(String) * @see Session#bySimpleNaturalId(String)
*/ */
public class NaturalIdentifier implements Criterion { public class NaturalIdentifier implements Criterion {
private final Conjunction conjunction = new Conjunction();
private final Junction conjunction = new Conjunction();
private final Map<String, Object> naturalIdValues = new HashMap<String, Object>();
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return conjunction.getTypedValues(criteria, criteriaQuery); return conjunction.getTypedValues( criteria, criteriaQuery );
} }
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException { public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return conjunction.toSqlString(criteria, criteriaQuery); return conjunction.toSqlString( criteria, criteriaQuery );
} }
public Map<String, Object> getNaturalIdValues() { public Map<String, Object> getNaturalIdValues() {
return naturalIdValues; final Map<String, Object> naturalIdValueMap = new ConcurrentHashMap<String, Object>();
for ( Criterion condition : conjunction.conditions() ) {
if ( !SimpleExpression.class.isInstance( condition ) ) {
continue;
}
final SimpleExpression equalsCondition = SimpleExpression.class.cast( condition );
if ( !"=".equals( equalsCondition.getOp() ) ) {
continue;
}
naturalIdValueMap.put( equalsCondition.getPropertyName(), equalsCondition.getValue() );
}
return naturalIdValueMap;
} }
public NaturalIdentifier set(String property, Object value) { public NaturalIdentifier set(String property, Object value) {
conjunction.add( Restrictions.eq(property, value) ); conjunction.add( Restrictions.eq( property, value ) );
naturalIdValues.put( property, value );
return this; return this;
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2008-2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,9 +20,9 @@
* 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.criterion; package org.hibernate.criterion;
import java.sql.Types; import java.sql.Types;
import org.hibernate.Criteria; import org.hibernate.Criteria;
@ -33,10 +33,10 @@
/** /**
* superclass for "simple" comparisons (with SQL binary operators) * superclass for "simple" comparisons (with SQL binary operators)
*
* @author Gavin King * @author Gavin King
*/ */
public class SimpleExpression implements Criterion { public class SimpleExpression implements Criterion {
private final String propertyName; private final String propertyName;
private final Object value; private final Object value;
private boolean ignoreCase; private boolean ignoreCase;
@ -61,35 +61,43 @@ public SimpleExpression ignoreCase() {
} }
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException { throws HibernateException {
String[] columns = criteriaQuery.findColumns(propertyName, criteria); String[] columns = criteriaQuery.findColumns( propertyName, criteria );
Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName); Type type = criteriaQuery.getTypeUsingProjection( criteria, propertyName );
StringBuffer fragment = new StringBuffer(); StringBuffer fragment = new StringBuffer();
if (columns.length>1) fragment.append('('); if ( columns.length > 1 ) {
fragment.append( '(' );
}
SessionFactoryImplementor factory = criteriaQuery.getFactory(); SessionFactoryImplementor factory = criteriaQuery.getFactory();
int[] sqlTypes = type.sqlTypes( factory ); int[] sqlTypes = type.sqlTypes( factory );
for ( int i=0; i<columns.length; i++ ) { for ( int i = 0; i < columns.length; i++ ) {
boolean lower = ignoreCase && boolean lower = ignoreCase &&
( sqlTypes[i]==Types.VARCHAR || sqlTypes[i]==Types.CHAR ); (sqlTypes[i] == Types.VARCHAR || sqlTypes[i] == Types.CHAR);
if (lower) { if ( lower ) {
fragment.append( factory.getDialect().getLowercaseFunction() ) fragment.append( factory.getDialect().getLowercaseFunction() )
.append('('); .append( '(' );
} }
fragment.append( columns[i] ); fragment.append( columns[i] );
if (lower) fragment.append(')'); if ( lower ) {
fragment.append( getOp() ).append("?"); fragment.append( ')' );
if ( i<columns.length-1 ) fragment.append(" and "); }
fragment.append( getOp() ).append( "?" );
if ( i < columns.length - 1 ) {
fragment.append( " and " );
}
}
if ( columns.length > 1 ) {
fragment.append( ')' );
} }
if (columns.length>1) fragment.append(')');
return fragment.toString(); return fragment.toString();
} }
public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
throws HibernateException { throws HibernateException {
Object icvalue = ignoreCase ? value.toString().toLowerCase() : value; Object icvalue = ignoreCase ? value.toString().toLowerCase() : value;
return new TypedValue[] { criteriaQuery.getTypedValue(criteria, propertyName, icvalue) }; return new TypedValue[] {criteriaQuery.getTypedValue( criteria, propertyName, icvalue )};
} }
public String toString() { public String toString() {
@ -100,4 +108,11 @@ protected final String getOp() {
return op; return op;
} }
public String getPropertyName() {
return propertyName;
}
public Object getValue() {
return value;
}
} }

View File

@ -1496,68 +1496,11 @@ public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) {
dontFlushFromFind--; dontFlushFromFind--;
} }
} }
/**
* Checks to see if the CriteriaImpl is a naturalId lookup that can be done via
* NaturalIdLoadAccess
*
* @return A fully configured NaturalIdLoadAccess or null, if null is returned the standard CriteriaImpl execution
* should be performed
*/
private NaturalIdLoadAccess tryNaturalIdLoadAccess(CriteriaImpl criteria) {
// See if the criteria lookup is by naturalId
if ( !criteria.isLookupByNaturalKey() ) {
return null;
}
final String entityName = criteria.getEntityOrClassName();
final EntityPersister entityPersister = factory.getEntityPersister( entityName );
// Verify the entity actually has a natural id, needed for legacy support as NaturalIdentifier criteria
// queries did no natural id validation
if ( !entityPersister.hasNaturalIdentifier() ) {
return null;
}
// Since isLookupByNaturalKey is true there can be only one CriterionEntry and getCriterion() will
// return an instanceof NaturalIdentifier
final CriterionEntry criterionEntry = (CriterionEntry) criteria.iterateExpressionEntries().next();
final NaturalIdentifier naturalIdentifier = (NaturalIdentifier) criterionEntry.getCriterion();
final Map<String, Object> naturalIdValues = naturalIdentifier.getNaturalIdValues();
final int[] naturalIdentifierProperties = entityPersister.getNaturalIdentifierProperties();
// Verify the NaturalIdentifier criterion includes all naturalId properties, first check that the property counts match
if ( naturalIdentifierProperties.length != naturalIdValues.size() ) {
return null;
}
final String[] propertyNames = entityPersister.getPropertyNames();
final NaturalIdLoadAccess naturalIdLoader = this.byNaturalId( entityName );
// Build NaturalIdLoadAccess and in the process verify all naturalId properties were specified
for ( int i = 0; i < naturalIdentifierProperties.length; i++ ) {
final String naturalIdProperty = propertyNames[naturalIdentifierProperties[i]];
final Object naturalIdValue = naturalIdValues.get( naturalIdProperty );
if ( naturalIdValue == null ) {
// A NaturalId property is missing from the critera query, can't use NaturalIdLoadAccess
return null;
}
naturalIdLoader.using( naturalIdProperty, naturalIdValue );
}
// Critera query contains a valid naturalId, use the new API
LOG.warn( "Session.byNaturalId(" + entityName
+ ") should be used for naturalId queries instead of Restrictions.naturalId() from a Criteria" );
return naturalIdLoader;
}
public List list(CriteriaImpl criteria) throws HibernateException { public List list(CriteriaImpl criteria) throws HibernateException {
final NaturalIdLoadAccess naturalIdLoadAccess = this.tryNaturalIdLoadAccess( criteria ); final NaturalIdLoadAccess naturalIdLoadAccess = this.tryNaturalIdLoadAccess( criteria );
if ( naturalIdLoadAccess != null ) { if ( naturalIdLoadAccess != null ) {
// EARLY EXIT!
return Arrays.asList( naturalIdLoadAccess.load() ); return Arrays.asList( naturalIdLoadAccess.load() );
} }
@ -1603,6 +1546,66 @@ public List list(CriteriaImpl criteria) throws HibernateException {
return results; return results;
} }
/**
* Checks to see if the CriteriaImpl is a naturalId lookup that can be done via
* NaturalIdLoadAccess
*
* @param criteria The criteria to check as a complete natural identifier lookup.
*
* @return A fully configured NaturalIdLoadAccess or null, if null is returned the standard CriteriaImpl execution
* should be performed
*/
private NaturalIdLoadAccess tryNaturalIdLoadAccess(CriteriaImpl criteria) {
// See if the criteria lookup is by naturalId
if ( !criteria.isLookupByNaturalKey() ) {
return null;
}
final String entityName = criteria.getEntityOrClassName();
final EntityPersister entityPersister = factory.getEntityPersister( entityName );
// Verify the entity actually has a natural id, needed for legacy support as NaturalIdentifier criteria
// queries did no natural id validation
if ( !entityPersister.hasNaturalIdentifier() ) {
return null;
}
// Since isLookupByNaturalKey is true there can be only one CriterionEntry and getCriterion() will
// return an instanceof NaturalIdentifier
final CriterionEntry criterionEntry = (CriterionEntry) criteria.iterateExpressionEntries().next();
final NaturalIdentifier naturalIdentifier = (NaturalIdentifier) criterionEntry.getCriterion();
final Map<String, Object> naturalIdValues = naturalIdentifier.getNaturalIdValues();
final int[] naturalIdentifierProperties = entityPersister.getNaturalIdentifierProperties();
// Verify the NaturalIdentifier criterion includes all naturalId properties, first check that the property counts match
if ( naturalIdentifierProperties.length != naturalIdValues.size() ) {
return null;
}
final String[] propertyNames = entityPersister.getPropertyNames();
final NaturalIdLoadAccess naturalIdLoader = this.byNaturalId( entityName );
// Build NaturalIdLoadAccess and in the process verify all naturalId properties were specified
for ( int i = 0; i < naturalIdentifierProperties.length; i++ ) {
final String naturalIdProperty = propertyNames[naturalIdentifierProperties[i]];
final Object naturalIdValue = naturalIdValues.get( naturalIdProperty );
if ( naturalIdValue == null ) {
// A NaturalId property is missing from the critera query, can't use NaturalIdLoadAccess
return null;
}
naturalIdLoader.using( naturalIdProperty, naturalIdValue );
}
// Critera query contains a valid naturalId, use the new API
LOG.warn( "Session.byNaturalId(" + entityName
+ ") should be used for naturalId queries instead of Restrictions.naturalId() from a Criteria" );
return naturalIdLoader;
}
private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException { private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException {
EntityPersister persister = factory.getEntityPersister(entityName); EntityPersister persister = factory.getEntityPersister(entityName);
if ( !(persister instanceof OuterJoinLoadable) ) { if ( !(persister instanceof OuterJoinLoadable) ) {