HHH-5426 - HQL update/delete does not invalidate the query cache

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@20143 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2010-08-13 22:29:41 +00:00
parent 36c471e579
commit b621e682d7
7 changed files with 156 additions and 100 deletions

View File

@ -193,7 +193,7 @@ public interface SessionFactory extends Referenceable, Serializable {
*
* @since 3.0 changed key from {@link Class} to {@link String}.
*/
public Map getAllClassMetadata();
public Map<String,ClassMetadata> getAllClassMetadata();
/**
* Get the {@link CollectionMetadata} for all mapped collections

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2010, Red Hat Inc. 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.
* distributed under license by Red Hat Inc.
*
* 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
@ -20,27 +20,25 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.action;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.cache.access.SoftLock;
import org.hibernate.cache.access.EntityRegionAccessStrategy;
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.cache.access.EntityRegionAccessStrategy;
import org.hibernate.cache.access.SoftLock;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Arrays;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Queryable;
/**
* An {@link org.hibernate.engine.ActionQueue} {@link Executable} for ensuring
@ -57,8 +55,8 @@ import java.util.Arrays;
public class BulkOperationCleanupAction implements Executable, Serializable {
private final Serializable[] affectedTableSpaces;
private final Set entityCleanups = new HashSet();
private final Set collectionCleanups = new HashSet();
private final Set<EntityCleanup> entityCleanups = new HashSet<EntityCleanup>();
private final Set<CollectionCleanup> collectionCleanups = new HashSet<CollectionCleanup>();
/**
* Constructs an action to cleanup "affected cache regions" based on the
@ -72,17 +70,17 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
*/
public BulkOperationCleanupAction(SessionImplementor session, Queryable[] affectedQueryables) {
SessionFactoryImplementor factory = session.getFactory();
ArrayList tmpSpaces = new ArrayList();
for ( int i = 0; i < affectedQueryables.length; i++ ) {
tmpSpaces.addAll( Arrays.asList( affectedQueryables[i].getQuerySpaces() ) );
if ( affectedQueryables[i].hasCache() ) {
entityCleanups.add( new EntityCleanup( affectedQueryables[i].getCacheAccessStrategy() ) );
LinkedHashSet<String> spacesList = new LinkedHashSet<String>();
for ( Queryable persister : affectedQueryables ) {
spacesList.addAll( Arrays.asList( (String[]) persister.getQuerySpaces() ) );
if ( persister.hasCache() ) {
entityCleanups.add( new EntityCleanup( persister.getCacheAccessStrategy() ) );
}
Set roles = factory.getCollectionRolesByEntityParticipant( affectedQueryables[i].getEntityName() );
Set<String> roles = factory.getCollectionRolesByEntityParticipant( persister.getEntityName() );
if ( roles != null ) {
Iterator itr = roles.iterator();
while ( itr.hasNext() ) {
String role = ( String ) itr.next();
for ( String role : roles ) {
CollectionPersister collectionPersister = factory.getCollectionPersister( role );
if ( collectionPersister.hasCache() ) {
collectionCleanups.add( new CollectionCleanup( collectionPersister.getCacheAccessStrategy() ) );
@ -91,14 +89,14 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
}
}
this.affectedTableSpaces = ( Serializable[] ) tmpSpaces.toArray( new Serializable[ tmpSpaces.size() ] );
this.affectedTableSpaces = spacesList.toArray( new String[ spacesList.size() ] );
}
/**
* Constructs an action to cleanup "affected cache regions" based on a
* set of affected table spaces. This differs from {@link #BulkOperationCleanupAction(SessionImplementor, Queryable[])}
* in that here we have the affected <strong>table names</strong>. From those
* we deduce the entity persisters whcih are affected based on the defined
* we deduce the entity persisters which are affected based on the defined
* {@link EntityPersister#getQuerySpaces() table spaces}; and from there, we
* determine the affected collection regions based on any collections
* in which those entity persisters participate as elements/keys/etc.
@ -106,26 +104,24 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
* @param session The session to which this request is tied.
* @param tableSpaces The table spaces.
*/
@SuppressWarnings({ "unchecked" })
public BulkOperationCleanupAction(SessionImplementor session, Set tableSpaces) {
Set tmpSpaces = new HashSet(tableSpaces);
SessionFactoryImplementor factory = session.getFactory();
Iterator iterator = factory.getAllClassMetadata().entrySet().iterator();
while ( iterator.hasNext() ) {
Map.Entry entry = (Map.Entry) iterator.next();
String entityName = (String) entry.getKey();
EntityPersister persister = factory.getEntityPersister( entityName );
Serializable[] entitySpaces = persister.getQuerySpaces();
LinkedHashSet<String> spacesList = new LinkedHashSet<String>();
spacesList.addAll( tableSpaces );
SessionFactoryImplementor factory = session.getFactory();
for ( String entityName : factory.getAllClassMetadata().keySet() ) {
final EntityPersister persister = factory.getEntityPersister( entityName );
final String[] entitySpaces = (String[]) persister.getQuerySpaces();
if ( affectedEntity( tableSpaces, entitySpaces ) ) {
tmpSpaces.addAll( Arrays.asList( entitySpaces ) );
spacesList.addAll( Arrays.asList( entitySpaces ) );
if ( persister.hasCache() ) {
entityCleanups.add( new EntityCleanup( persister.getCacheAccessStrategy() ) );
}
Set roles = session.getFactory().getCollectionRolesByEntityParticipant( persister.getEntityName() );
Set<String> roles = session.getFactory().getCollectionRolesByEntityParticipant( persister.getEntityName() );
if ( roles != null ) {
Iterator itr = roles.iterator();
while ( itr.hasNext() ) {
String role = ( String ) itr.next();
for ( String role : roles ) {
CollectionPersister collectionPersister = factory.getCollectionPersister( role );
if ( collectionPersister.hasCache() ) {
collectionCleanups.add(
@ -137,7 +133,7 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
}
}
this.affectedTableSpaces = ( Serializable[] ) tmpSpaces.toArray( new Serializable[ tmpSpaces.size() ] );
this.affectedTableSpaces = spacesList.toArray( new String[ spacesList.size() ] );
}
@ -158,8 +154,8 @@ public class BulkOperationCleanupAction implements Executable, Serializable {
return true;
}
for ( int i = 0; i < checkTableSpaces.length; i++ ) {
if ( affectedTableSpaces.contains( checkTableSpaces[i] ) ) {
for ( Serializable checkTableSpace : checkTableSpaces ) {
if ( affectedTableSpaces.contains( checkTableSpace ) ) {
return true;
}
}

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* Copyright (c) 2010, Red Hat Inc. 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.
* distributed under license by Red Hat Inc.
*
* 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
@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.engine;
@ -30,17 +29,18 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.action.AfterTransactionCompletionProcess;
import org.hibernate.action.BeforeTransactionCompletionProcess;
import org.hibernate.action.BulkOperationCleanupAction;
import org.hibernate.action.CollectionRecreateAction;
import org.hibernate.action.CollectionRemoveAction;
@ -50,8 +50,6 @@ import org.hibernate.action.EntityIdentityInsertAction;
import org.hibernate.action.EntityInsertAction;
import org.hibernate.action.EntityUpdateAction;
import org.hibernate.action.Executable;
import org.hibernate.action.AfterTransactionCompletionProcess;
import org.hibernate.action.BeforeTransactionCompletionProcess;
import org.hibernate.cache.CacheException;
import org.hibernate.type.Type;
@ -121,36 +119,43 @@ public class ActionQueue {
collectionUpdates.clear();
}
@SuppressWarnings({ "unchecked" })
public void addAction(EntityInsertAction action) {
insertions.add( action );
}
@SuppressWarnings({ "unchecked" })
public void addAction(EntityDeleteAction action) {
deletions.add( action );
}
@SuppressWarnings({ "unchecked" })
public void addAction(EntityUpdateAction action) {
updates.add( action );
}
@SuppressWarnings({ "unchecked" })
public void addAction(CollectionRecreateAction action) {
collectionCreations.add( action );
}
@SuppressWarnings({ "unchecked" })
public void addAction(CollectionRemoveAction action) {
collectionRemovals.add( action );
}
@SuppressWarnings({ "unchecked" })
public void addAction(CollectionUpdateAction action) {
collectionUpdates.add( action );
}
@SuppressWarnings({ "unchecked" })
public void addAction(EntityIdentityInsertAction insert) {
insertions.add( insert );
}
public void addAction(BulkOperationCleanupAction cleanupAction) {
registerProcess( cleanupAction.getAfterTransactionCompletionProcess() );
registerCleanupActions( cleanupAction );
}
public void registerProcess(AfterTransactionCompletionProcess process) {
@ -238,14 +243,14 @@ public class ActionQueue {
return ( insertions.size() > 0 || deletions.size() > 0 );
}
private static boolean areTablesToUpdated(List executables, Set tablespaces) {
int size = executables.size();
for ( int j = 0; j < size; j++ ) {
Serializable[] spaces = ( ( Executable ) executables.get( j ) ).getPropertySpaces();
for ( int i = 0; i < spaces.length; i++ ) {
if ( tablespaces.contains( spaces[i] ) ) {
@SuppressWarnings({ "unchecked" })
private static boolean areTablesToUpdated(List actions, Set tableSpaces) {
for ( Executable action : (List<Executable>) actions ) {
final Serializable[] spaces = action.getPropertySpaces();
for ( Serializable space : spaces ) {
if ( tableSpaces.contains( space ) ) {
if ( log.isDebugEnabled() ) {
log.debug( "changes must be flushed to space: " + spaces[i] );
log.debug( "changes must be flushed to space: " + space );
}
return true;
}
@ -268,20 +273,23 @@ public class ActionQueue {
executable.execute();
}
finally {
beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
if ( session.getFactory().getSettings().isQueryCacheEnabled() ) {
final String[] spaces = (String[]) executable.getPropertySpaces();
afterTransactionProcesses.addSpacesToInvalidate( spaces );
session.getFactory().getUpdateTimestampsCache().preinvalidate( executable.getPropertySpaces() );
}
afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() );
registerCleanupActions( executable );
}
}
private void registerCleanupActions(Executable executable) {
beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
if ( session.getFactory().getSettings().isQueryCacheEnabled() ) {
final String[] spaces = (String[]) executable.getPropertySpaces();
afterTransactionProcesses.addSpacesToInvalidate( spaces );
session.getFactory().getUpdateTimestampsCache().preinvalidate( spaces );
}
afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() );
}
@SuppressWarnings({ "unchecked" })
private void prepareActions(List queue) throws HibernateException {
int size = queue.size();
for ( int i = 0; i < size; i++ ) {
Executable executable = ( Executable ) queue.get( i );
for ( Executable executable : (List<Executable>) queue ) {
executable.beforeExecutions();
}
}
@ -327,6 +335,7 @@ public class ActionQueue {
return insertions.size();
}
@SuppressWarnings({ "unchecked" })
public void sortCollectionActions() {
if ( session.getFactory().getSettings().isOrderUpdatesEnabled() ) {
//sort the updates by fk
@ -336,6 +345,7 @@ public class ActionQueue {
}
}
@SuppressWarnings({ "unchecked" })
public void sortActions() {
if ( session.getFactory().getSettings().isOrderUpdatesEnabled() ) {
//sort the updates by pk
@ -359,6 +369,7 @@ public class ActionQueue {
new InsertActionSorter().sort();
}
@SuppressWarnings({ "UnusedDeclaration" })
public ArrayList cloneDeletions() {
return ( ArrayList ) deletions.clone();
}
@ -374,6 +385,7 @@ public class ActionQueue {
}
}
@SuppressWarnings({ "UnusedDeclaration" })
public boolean hasAfterTransactionActions() {
return afterTransactionProcesses.processes.size() > 0;
}
@ -457,6 +469,7 @@ public class ActionQueue {
* @throws IOException indicates a problem reading from the stream
* @throws ClassNotFoundException Generally means we were unable to locate user classes.
*/
@SuppressWarnings({ "unchecked" })
public static ActionQueue deserialize(
ObjectInputStream ois,
SessionImplementor session) throws IOException, ClassNotFoundException {
@ -465,42 +478,42 @@ public class ActionQueue {
int queueSize = ois.readInt();
log.trace( "starting deserialization of [" + queueSize + "] insertions entries" );
rtn.insertions = new ArrayList( queueSize );
rtn.insertions = new ArrayList<Executable>( queueSize );
for ( int i = 0; i < queueSize; i++ ) {
rtn.insertions.add( ois.readObject() );
}
queueSize = ois.readInt();
log.trace( "starting deserialization of [" + queueSize + "] deletions entries" );
rtn.deletions = new ArrayList( queueSize );
rtn.deletions = new ArrayList<Executable>( queueSize );
for ( int i = 0; i < queueSize; i++ ) {
rtn.deletions.add( ois.readObject() );
}
queueSize = ois.readInt();
log.trace( "starting deserialization of [" + queueSize + "] updates entries" );
rtn.updates = new ArrayList( queueSize );
rtn.updates = new ArrayList<Executable>( queueSize );
for ( int i = 0; i < queueSize; i++ ) {
rtn.updates.add( ois.readObject() );
}
queueSize = ois.readInt();
log.trace( "starting deserialization of [" + queueSize + "] collectionUpdates entries" );
rtn.collectionUpdates = new ArrayList( queueSize );
rtn.collectionUpdates = new ArrayList<Executable>( queueSize );
for ( int i = 0; i < queueSize; i++ ) {
rtn.collectionUpdates.add( ois.readObject() );
}
queueSize = ois.readInt();
log.trace( "starting deserialization of [" + queueSize + "] collectionRemovals entries" );
rtn.collectionRemovals = new ArrayList( queueSize );
rtn.collectionRemovals = new ArrayList<Executable>( queueSize );
for ( int i = 0; i < queueSize; i++ ) {
rtn.collectionRemovals.add( ois.readObject() );
}
queueSize = ois.readInt();
log.trace( "starting deserialization of [" + queueSize + "] collectionCreations entries" );
rtn.collectionCreations = new ArrayList( queueSize );
rtn.collectionCreations = new ArrayList<Executable>( queueSize );
for ( int i = 0; i < queueSize; i++ ) {
rtn.collectionCreations.add( ois.readObject() );
}
@ -509,7 +522,7 @@ public class ActionQueue {
private static class BeforeTransactionCompletionProcessQueue {
private SessionImplementor session;
private List processes = new ArrayList();
private List<BeforeTransactionCompletionProcess> processes = new ArrayList<BeforeTransactionCompletionProcess>();
private BeforeTransactionCompletionProcessQueue(SessionImplementor session) {
this.session = session;
@ -526,7 +539,7 @@ public class ActionQueue {
final int size = processes.size();
for ( int i = 0; i < size; i++ ) {
try {
BeforeTransactionCompletionProcess process = ( BeforeTransactionCompletionProcess ) processes.get( i );
BeforeTransactionCompletionProcess process = processes.get( i );
process.doBeforeTransactionCompletion( session );
}
catch ( HibernateException he ) {
@ -542,8 +555,9 @@ public class ActionQueue {
private static class AfterTransactionCompletionProcessQueue {
private SessionImplementor session;
private Set querySpacesToInvalidate = new HashSet();
private List processes = new ArrayList( INIT_QUEUE_LIST_SIZE * 3 );
private Set<String> querySpacesToInvalidate = new HashSet<String>();
private List<AfterTransactionCompletionProcess> processes
= new ArrayList<AfterTransactionCompletionProcess>( INIT_QUEUE_LIST_SIZE * 3 );
private AfterTransactionCompletionProcessQueue(SessionImplementor session) {
this.session = session;
@ -573,7 +587,7 @@ public class ActionQueue {
final int size = processes.size();
for ( int i = 0; i < size; i++ ) {
try {
AfterTransactionCompletionProcess process = ( AfterTransactionCompletionProcess ) processes.get( i );
AfterTransactionCompletionProcess process = processes.get( i );
process.doAfterTransactionCompletion( success, session );
}
catch ( CacheException ce ) {
@ -588,7 +602,7 @@ public class ActionQueue {
if ( session.getFactory().getSettings().isQueryCacheEnabled() ) {
session.getFactory().getUpdateTimestampsCache().invalidate(
( String[] ) querySpacesToInvalidate.toArray( new String[ querySpacesToInvalidate.size()] )
querySpacesToInvalidate.toArray( new String[ querySpacesToInvalidate.size()] )
);
}
querySpacesToInvalidate.clear();
@ -616,11 +630,10 @@ public class ActionQueue {
/**
* Sort the insert actions.
*/
@SuppressWarnings({ "unchecked", "UnnecessaryBoxing" })
public void sort() {
// the list of entity names that indicate the batch number
for ( Iterator actionItr = insertions.iterator(); actionItr.hasNext(); ) {
EntityInsertAction action = ( EntityInsertAction ) actionItr.next();
for ( EntityInsertAction action : (List<EntityInsertAction>) insertions ) {
// remove the current element from insertions. It will be added back later.
String entityName = action.getEntityName();
@ -641,7 +654,7 @@ public class ActionQueue {
// doing the batch number before adding the name to the list is
// a faster way to get an accurate number.
batchNumber = new Integer( actionBatches.size() );
batchNumber = Integer.valueOf( actionBatches.size() );
latestBatches.put( entityName, batchNumber );
}
entityBatchNumber.put( currentEntity, batchNumber );
@ -652,8 +665,8 @@ public class ActionQueue {
// now rebuild the insertions list. There is a batch for each entry in the name list.
for ( int i = 0; i < actionBatches.size(); i++ ) {
List batch = ( List ) actionBatches.get( new Integer( i ) );
for ( Iterator batchItr = batch.iterator(); batchItr.hasNext(); ) {
EntityInsertAction action = ( EntityInsertAction ) batchItr.next();
for ( Object aBatch : batch ) {
EntityInsertAction action = (EntityInsertAction) aBatch;
insertions.add( action );
}
}
@ -667,6 +680,7 @@ public class ActionQueue {
*
* @return An appropriate batch number; todo document this process better
*/
@SuppressWarnings({ "UnnecessaryBoxing", "unchecked" })
private Integer findBatchNumber(
EntityInsertAction action,
String entityName) {
@ -691,7 +705,7 @@ public class ActionQueue {
Integer associationBatchNumber = ( Integer ) entityBatchNumber.get( value );
if ( associationBatchNumber != null && associationBatchNumber.compareTo( latestBatchNumberForType ) > 0 ) {
// create a new batch for this type. The batch number is the number of current batches.
latestBatchNumberForType = new Integer( actionBatches.size() );
latestBatchNumberForType = Integer.valueOf( actionBatches.size() );
latestBatches.put( entityName, latestBatchNumberForType );
// since this entity will now be processed in the latest possible batch,
// we can be assured that it will come after all other associations,
@ -703,6 +717,7 @@ public class ActionQueue {
return latestBatchNumberForType;
}
@SuppressWarnings({ "unchecked" })
private void addToBatch(Integer batchNumber, EntityInsertAction action) {
List actions = ( List ) actionBatches.get( batchNumber );

View File

@ -230,7 +230,7 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
* @param entityName The entity name for which to get the collection roles.
* @return set of all the collection roles in which the given entityName participates.
*/
public Set getCollectionRolesByEntityParticipant(String entityName);
public Set<String> getCollectionRolesByEntityParticipant(String entityName);
public EntityNotFoundDelegate getEntityNotFoundDelegate();

View File

@ -158,10 +158,10 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
private final String uuid;
private final transient Map entityPersisters;
private final transient Map classMetadata;
private final transient Map<String,ClassMetadata> classMetadata;
private final transient Map collectionPersisters;
private final transient Map collectionMetadata;
private final transient Map collectionRolesByEntityParticipant;
private final transient Map<String,Set<String>> collectionRolesByEntityParticipant;
private final transient Map identifierGenerators;
private final transient Map namedQueries;
private final transient Map namedSqlQueries;
@ -263,7 +263,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
entityPersisters = new HashMap();
Map entityAccessStrategies = new HashMap();
Map classMeta = new HashMap();
Map<String,ClassMetadata> classMeta = new HashMap<String,ClassMetadata>();
classes = cfg.getClassMappings();
while ( classes.hasNext() ) {
final PersistentClass model = (PersistentClass) classes.next();
@ -285,9 +285,9 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
entityPersisters.put( model.getEntityName(), cp );
classMeta.put( model.getEntityName(), cp.getClassMetadata() );
}
classMetadata = Collections.unmodifiableMap(classMeta);
this.classMetadata = Collections.unmodifiableMap(classMeta);
Map tmpEntityToCollectionRoleMap = new HashMap();
Map<String,Set<String>> tmpEntityToCollectionRoleMap = new HashMap<String,Set<String>>();
collectionPersisters = new HashMap();
Iterator collections = cfg.getCollectionMappings();
while ( collections.hasNext() ) {
@ -726,8 +726,8 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
return settings.getSQLExceptionConverter();
}
public Set getCollectionRolesByEntityParticipant(String entityName) {
return ( Set ) collectionRolesByEntityParticipant.get( entityName );
public Set<String> getCollectionRolesByEntityParticipant(String entityName) {
return collectionRolesByEntityParticipant.get( entityName );
}
// from javax.naming.Referenceable
@ -884,7 +884,7 @@ public final class SessionFactoryImpl implements SessionFactory, SessionFactoryI
}
}
public Map getAllClassMetadata() throws HibernateException {
public Map<String,ClassMetadata> getAllClassMetadata() throws HibernateException {
return classMetadata;
}

View File

@ -131,7 +131,7 @@ public class SessionFactoryStub implements SessionFactory {
return getImpl().getCollectionMetadata(roleName);
}
public Map getAllClassMetadata() throws HibernateException {
public Map<String,ClassMetadata> getAllClassMetadata() throws HibernateException {
return getImpl().getAllClassMetadata();
}

View File

@ -42,6 +42,51 @@ public class QueryCacheTest extends FunctionalTestCase {
public static Test suite() {
return new FunctionalTestClassTestSuite( QueryCacheTest.class );
}
public void testInvalidationFromBulkHQL() {
// http://opensource.atlassian.com/projects/hibernate/browse/HHH-5426
getSessions().getCache().evictQueryRegions();
getSessions().getStatistics().clear();
Session s = openSession();
List list = new ArrayList();
s.beginTransaction();
for (int i = 0; i < 3; i++) {
Item a = new Item();
a.setName("a" + i);
a.setDescription("a" + i);
list.add(a);
s.persist(a);
}
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
String queryString = "select count(*) from Item";
// this query will hit the database and create the cache
Long result = (Long) s.createQuery(queryString).setCacheable(true).uniqueResult();
assertEquals(3, result.intValue());
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
String updateString = "delete from Item";
s.createQuery(updateString).executeUpdate();
s.getTransaction().commit();
s.close();
s = openSession();
s.beginTransaction();
// and this one SHOULD not be served by the cache
Number result2 = (Number) s.createQuery(queryString).setCacheable(true).uniqueResult();
assertEquals(0, result2.intValue());
s.getTransaction().commit();
s.close();
}
//https://jira.jboss.org/jira/browse/JBPAPP-4224
public void testHitCacheInSameSession() {
getSessions().evictQueries();