HHH-5697 - Support for multi-tenancy

This commit is contained in:
Steve Ebersole 2011-03-26 10:50:18 -05:00
parent fe8c7183d1
commit 47abaf12fa
24 changed files with 622 additions and 537 deletions

View File

@ -85,19 +85,14 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
@Override @Override
public final void beforeExecutions() throws CacheException { public final void beforeExecutions() throws CacheException {
// we need to obtain the lock before any actions are // we need to obtain the lock before any actions are executed, since this may be an inverse="true"
// executed, since this may be an inverse="true" // bidirectional association and it is one of the earlier entity actions which actually updates
// bidirectional association and it is one of the // the database (this action is responsible for second-level cache invalidation only)
// earlier entity actions which actually updates
// the database (this action is resposible for
// second-level cache invalidation only)
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
final CacheKey ck = new CacheKey( final CacheKey ck = session.generateCacheKey(
key, key,
persister.getKeyType(), persister.getKeyType(),
persister.getRole(), persister.getRole()
session.getEntityMode(),
session.getFactory()
); );
final SoftLock lock = persister.getCacheAccessStrategy().lockItem( ck, null ); final SoftLock lock = persister.getCacheAccessStrategy().lockItem( ck, null );
// the old behavior used key as opposed to getKey() // the old behavior used key as opposed to getKey()
@ -145,12 +140,10 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
protected final void evict() throws CacheException { protected final void evict() throws CacheException {
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
CacheKey ck = new CacheKey( CacheKey ck = session.generateCacheKey(
key, key,
persister.getKeyType(), persister.getKeyType(),
persister.getRole(), persister.getRole()
session.getEntityMode(),
session.getFactory()
); );
persister.getCacheAccessStrategy().remove( ck ); persister.getCacheAccessStrategy().remove( ck );
} }
@ -190,12 +183,10 @@ public abstract class CollectionAction implements Executable, Serializable, Comp
@Override @Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) { public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
final CacheKey ck = new CacheKey( final CacheKey ck = session.generateCacheKey(
key, key,
persister.getKeyType(), persister.getKeyType(),
persister.getRole(), persister.getRole()
session.getEntityMode(),
session.getFactory()
); );
persister.getCacheAccessStrategy().unlockItem( ck, lock ); persister.getCacheAccessStrategy().unlockItem( ck, lock );
} }

View File

@ -79,13 +79,7 @@ public final class EntityDeleteAction extends EntityAction {
final CacheKey ck; final CacheKey ck;
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
ck = new CacheKey( ck = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
id,
persister.getIdentifierType(),
persister.getRootEntityName(),
session.getEntityMode(),
session.getFactory()
);
lock = persister.getCacheAccessStrategy().lockItem( ck, version ); lock = persister.getCacheAccessStrategy().lockItem( ck, version );
} }
else { else {
@ -170,12 +164,10 @@ public final class EntityDeleteAction extends EntityAction {
@Override @Override
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) throws HibernateException { public void doAfterTransactionCompletion(boolean success, SessionImplementor session) throws HibernateException {
if ( getPersister().hasCache() ) { if ( getPersister().hasCache() ) {
final CacheKey ck = new CacheKey( final CacheKey ck = getSession().generateCacheKey(
getId(), getId(),
getPersister().getIdentifierType(), getPersister().getIdentifierType(),
getPersister().getRootEntityName(), getPersister().getRootEntityName()
getSession().getEntityMode(),
getSession().getFactory()
); );
getPersister().getCacheAccessStrategy().unlockItem( ck, lock ); getPersister().getCacheAccessStrategy().unlockItem( ck, lock );
} }

View File

@ -110,13 +110,7 @@ public final class EntityInsertAction extends EntityAction {
); );
cacheEntry = persister.getCacheEntryStructure().structure(ce); cacheEntry = persister.getCacheEntryStructure().structure(ce);
final CacheKey ck = new CacheKey( final CacheKey ck = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
id,
persister.getIdentifierType(),
persister.getRootEntityName(),
session.getEntityMode(),
session.getFactory()
);
boolean put = persister.getCacheAccessStrategy().insert( ck, cacheEntry, version ); boolean put = persister.getCacheAccessStrategy().insert( ck, cacheEntry, version );
if ( put && factory.getStatistics().isStatisticsEnabled() ) { if ( put && factory.getStatistics().isStatisticsEnabled() ) {
@ -185,13 +179,7 @@ public final class EntityInsertAction extends EntityAction {
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) throws HibernateException { public void doAfterTransactionCompletion(boolean success, SessionImplementor session) throws HibernateException {
EntityPersister persister = getPersister(); EntityPersister persister = getPersister();
if ( success && isCachePutEnabled( persister, getSession() ) ) { if ( success && isCachePutEnabled( persister, getSession() ) ) {
final CacheKey ck = new CacheKey( final CacheKey ck = getSession().generateCacheKey( getId(), persister.getIdentifierType(), persister.getRootEntityName() );
getId(),
persister.getIdentifierType(),
persister.getRootEntityName(),
getSession().getEntityMode(),
getSession().getFactory()
);
boolean put = persister.getCacheAccessStrategy().afterInsert( ck, cacheEntry, version ); boolean put = persister.getCacheAccessStrategy().afterInsert( ck, cacheEntry, version );
if ( put && getSession().getFactory().getStatistics().isStatisticsEnabled() ) { if ( put && getSession().getFactory().getStatistics().isStatisticsEnabled() ) {

View File

@ -97,12 +97,10 @@ public final class EntityUpdateAction extends EntityAction {
final CacheKey ck; final CacheKey ck;
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
ck = new CacheKey( ck = session.generateCacheKey(
id, id,
persister.getIdentifierType(), persister.getIdentifierType(),
persister.getRootEntityName(), persister.getRootEntityName()
session.getEntityMode(),
session.getFactory()
); );
lock = persister.getCacheAccessStrategy().lockItem( ck, previousVersion ); lock = persister.getCacheAccessStrategy().lockItem( ck, previousVersion );
} }
@ -251,12 +249,10 @@ public final class EntityUpdateAction extends EntityAction {
EntityPersister persister = getPersister(); EntityPersister persister = getPersister();
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
final CacheKey ck = new CacheKey( final CacheKey ck = getSession().generateCacheKey(
getId(), getId(),
persister.getIdentifierType(), persister.getIdentifierType(),
persister.getRootEntityName(), persister.getRootEntityName()
getSession().getEntityMode(),
getSession().getFactory()
); );
if ( success && cacheEntry!=null /*!persister.isCacheInvalidationRequired()*/ ) { if ( success && cacheEntry!=null /*!persister.isCacheInvalidationRequired()*/ ) {

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-2011, 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,12 +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.cache; package org.hibernate.cache;
import java.io.Serializable; import java.io.Serializable;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.type.Type; import org.hibernate.type.Type;
/** /**
@ -40,6 +42,7 @@ public class CacheKey implements Serializable {
private final Type type; private final Type type;
private final String entityOrRoleName; private final String entityOrRoleName;
private final EntityMode entityMode; private final EntityMode entityMode;
private final String tenantId;
private final int hashCode; private final int hashCode;
/** /**
@ -50,7 +53,8 @@ public class CacheKey implements Serializable {
* @param id The identifier associated with the cached data * @param id The identifier associated with the cached data
* @param type The Hibernate type mapping * @param type The Hibernate type mapping
* @param entityOrRoleName The entity or collection-role name. * @param entityOrRoleName The entity or collection-role name.
* @param entityMode The entiyt mode of the originating session * @param entityMode The entity mode of the originating session
* @param tenantId The tenant identifier associated this data.
* @param factory The session factory for which we are caching * @param factory The session factory for which we are caching
*/ */
public CacheKey( public CacheKey(
@ -58,26 +62,34 @@ public class CacheKey implements Serializable {
final Type type, final Type type,
final String entityOrRoleName, final String entityOrRoleName,
final EntityMode entityMode, final EntityMode entityMode,
final String tenantId,
final SessionFactoryImplementor factory) { final SessionFactoryImplementor factory) {
this.key = id; this.key = id;
this.type = type; this.type = type;
this.entityOrRoleName = entityOrRoleName; this.entityOrRoleName = entityOrRoleName;
this.entityMode = entityMode; this.entityMode = entityMode;
hashCode = type.getHashCode( key, entityMode, factory ); this.tenantId = tenantId;
this.hashCode = type.getHashCode( key, entityMode, factory );
} }
//Mainly for OSCache @Override
public String toString() { public String toString() {
// Mainly for OSCache
return entityOrRoleName + '#' + key.toString();//"CacheKey#" + type.toString(key, sf); return entityOrRoleName + '#' + key.toString();//"CacheKey#" + type.toString(key, sf);
} }
@Override
public boolean equals(Object other) { public boolean equals(Object other) {
if ( !(other instanceof CacheKey) ) return false; if ( !(other instanceof CacheKey) ) {
return false;
}
CacheKey that = (CacheKey) other; CacheKey that = (CacheKey) other;
return entityOrRoleName.equals( that.entityOrRoleName ) return entityOrRoleName.equals( that.entityOrRoleName ) &&
&& type.isEqual( key, that.key, entityMode ); type.isEqual( key, that.key, entityMode ) &&
EqualsHelper.equals( tenantId, that.tenantId );
} }
@Override
public int hashCode() { public int hashCode() {
return hashCode; return hashCode;
} }

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) 2--8-2011, 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,20 +20,21 @@
* 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.engine; package org.hibernate.engine;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.cache.CacheKey; import org.hibernate.cache.CacheKey;
import org.hibernate.collection.PersistentCollection; import org.hibernate.collection.PersistentCollection;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.internal.util.MarkerObject;
/** /**
* Tracks entity and collection keys that are available for batch * Tracks entity and collection keys that are available for batch
@ -198,7 +199,7 @@ public class BatchFetchQueue {
end = i; end = i;
//checkForEnd = false; //checkForEnd = false;
} }
else if ( !isCached( ce.getLoadedKey(), collectionPersister, entityMode ) ) { else if ( !isCached( ce.getLoadedKey(), collectionPersister ) ) {
keys[i++] = ce.getLoadedKey(); keys[i++] = ce.getLoadedKey();
//count++; //count++;
} }
@ -248,7 +249,7 @@ public class BatchFetchQueue {
end = i; end = i;
} }
else { else {
if ( !isCached( key, persister, entityMode ) ) { if ( !isCached( key, persister ) ) {
ids[i++] = key.getIdentifier(); ids[i++] = key.getIdentifier();
} }
} }
@ -261,34 +262,24 @@ public class BatchFetchQueue {
return ids; //we ran out of ids to try return ids; //we ran out of ids to try
} }
private boolean isCached( private boolean isCached(EntityKey entityKey, EntityPersister persister) {
EntityKey entityKey,
EntityPersister persister,
EntityMode entityMode) {
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
CacheKey key = new CacheKey( CacheKey key = context.getSession().generateCacheKey(
entityKey.getIdentifier(), entityKey.getIdentifier(),
persister.getIdentifierType(), persister.getIdentifierType(),
entityKey.getEntityName(), entityKey.getEntityName()
entityMode,
context.getSession().getFactory()
); );
return persister.getCacheAccessStrategy().get( key, context.getSession().getTimestamp() ) != null; return persister.getCacheAccessStrategy().get( key, context.getSession().getTimestamp() ) != null;
} }
return false; return false;
} }
private boolean isCached( private boolean isCached(Serializable collectionKey, CollectionPersister persister) {
Serializable collectionKey,
CollectionPersister persister,
EntityMode entityMode) {
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
CacheKey cacheKey = new CacheKey( CacheKey cacheKey = context.getSession().generateCacheKey(
collectionKey, collectionKey,
persister.getKeyType(), persister.getKeyType(),
persister.getRole(), persister.getRole()
entityMode,
context.getSession().getFactory()
); );
return persister.getCacheAccessStrategy().get( cacheKey, context.getSession().getTimestamp() ) != null; return persister.getCacheAccessStrategy().get( cacheKey, context.getSession().getTimestamp() ) != null;
} }

View File

@ -340,17 +340,17 @@ public final class EntityEntry implements Serializable {
* @throws IOException If a stream error occurs * @throws IOException If a stream error occurs
*/ */
void serialize(ObjectOutputStream oos) throws IOException { void serialize(ObjectOutputStream oos) throws IOException {
oos.writeUTF( entityName ); oos.writeObject( entityName );
oos.writeObject( id ); oos.writeObject( id );
oos.writeUTF( entityMode.toString() ); oos.writeObject( entityMode.toString() );
oos.writeUTF( tenantId ); oos.writeObject( tenantId );
oos.writeUTF( status.toString() ); oos.writeObject( status.toString() );
oos.writeUTF( ( previousStatus == null ? "" : previousStatus.toString() ) ); oos.writeObject( (previousStatus == null ? "" : previousStatus.toString()) );
// todo : potentially look at optimizing these two arrays // todo : potentially look at optimizing these two arrays
oos.writeObject( loadedState ); oos.writeObject( loadedState );
oos.writeObject( deletedState ); oos.writeObject( deletedState );
oos.writeObject( version ); oos.writeObject( version );
oos.writeUTF( lockMode.toString() ); oos.writeObject( lockMode.toString() );
oos.writeBoolean( existsInDatabase ); oos.writeBoolean( existsInDatabase );
oos.writeBoolean( isBeingReplicated ); oos.writeBoolean( isBeingReplicated );
oos.writeBoolean( loadedWithLazyPropertiesUnfetched ); oos.writeBoolean( loadedWithLazyPropertiesUnfetched );
@ -375,11 +375,11 @@ public final class EntityEntry implements Serializable {
String previousStatusString = null; String previousStatusString = null;
return new EntityEntry( return new EntityEntry(
( session == null ? null : session.getFactory() ), ( session == null ? null : session.getFactory() ),
ois.readUTF(), (String) ois.readObject(),
( Serializable ) ois.readObject(), ( Serializable ) ois.readObject(),
EntityMode.parse( ois.readUTF() ), EntityMode.parse( (String) ois.readObject() ),
ois.readUTF(), (String) ois.readObject(),
Status.parse( ois.readUTF() ), Status.parse( (String) ois.readObject() ),
( ( previousStatusString = ( String ) ois.readObject() ).length() == 0 ? ( ( previousStatusString = ( String ) ois.readObject() ).length() == 0 ?
null : null :
Status.parse( previousStatusString ) Status.parse( previousStatusString )
@ -387,7 +387,7 @@ public final class EntityEntry implements Serializable {
( Object[] ) ois.readObject(), ( Object[] ) ois.readObject(),
( Object[] ) ois.readObject(), ( Object[] ) ois.readObject(),
ois.readObject(), ois.readObject(),
LockMode.parse( ois.readUTF() ), LockMode.parse( (String) ois.readObject() ),
ois.readBoolean(), ois.readBoolean(),
ois.readBoolean(), ois.readBoolean(),
ois.readBoolean() ois.readBoolean()

View File

@ -30,6 +30,7 @@ import java.io.Serializable;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -137,7 +138,8 @@ public final class EntityKey implements Serializable {
public boolean equals(Object other) { public boolean equals(Object other) {
EntityKey otherKey = (EntityKey) other; EntityKey otherKey = (EntityKey) other;
return otherKey.rootEntityName.equals(this.rootEntityName) && return otherKey.rootEntityName.equals(this.rootEntityName) &&
identifierType.isEqual(otherKey.identifier, this.identifier, entityMode, factory); identifierType.isEqual(otherKey.identifier, this.identifier, entityMode, factory) &&
EqualsHelper.equals( tenantId, otherKey.tenantId );
} }
@Override @Override
@ -161,12 +163,12 @@ public final class EntityKey implements Serializable {
*/ */
void serialize(ObjectOutputStream oos) throws IOException { void serialize(ObjectOutputStream oos) throws IOException {
oos.writeObject( identifier ); oos.writeObject( identifier );
oos.writeUTF( rootEntityName ); oos.writeObject( rootEntityName );
oos.writeUTF( entityName ); oos.writeObject( entityName );
oos.writeObject( identifierType ); oos.writeObject( identifierType );
oos.writeBoolean( isBatchLoadable ); oos.writeBoolean( isBatchLoadable );
oos.writeUTF( entityMode.toString() ); oos.writeObject( entityMode.toString() );
oos.writeUTF( tenantId ); oos.writeObject( tenantId );
} }
/** /**
@ -186,13 +188,13 @@ public final class EntityKey implements Serializable {
SessionImplementor session) throws IOException, ClassNotFoundException { SessionImplementor session) throws IOException, ClassNotFoundException {
return new EntityKey( return new EntityKey(
( Serializable ) ois.readObject(), ( Serializable ) ois.readObject(),
ois.readUTF(), (String) ois.readObject(),
ois.readUTF(), (String) ois.readObject(),
( Type ) ois.readObject(), ( Type ) ois.readObject(),
ois.readBoolean(), ois.readBoolean(),
( session == null ? null : session.getFactory() ), ( session == null ? null : session.getFactory() ),
EntityMode.parse( ois.readUTF() ), EntityMode.parse( (String) ois.readObject() ),
ois.readUTF() (String) ois.readObject()
); );
} }
} }

View File

@ -36,6 +36,7 @@ import org.hibernate.Interceptor;
import org.hibernate.Query; import org.hibernate.Query;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.cache.CacheKey;
import org.hibernate.collection.PersistentCollection; import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.jdbc.LobCreationContext; import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
@ -80,6 +81,17 @@ public interface SessionImplementor extends Serializable, LobCreationContext {
*/ */
public EntityKey generateEntityKey(Serializable id, EntityPersister persister); public EntityKey generateEntityKey(Serializable id, EntityPersister persister);
/**
* Hide the changing requirements of cache key creation.
*
* @param id The entity identifier or collection key.
* @param type The type
* @param entityOrRoleName The entity name or collection role.
*
* @return The cache key
*/
public CacheKey generateCacheKey(Serializable id, final Type type, final String entityOrRoleName);
/** /**
* Retrieves the interceptor currently in use by this event source. * Retrieves the interceptor currently in use by this event source.
* *

View File

@ -22,26 +22,29 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.engine; package org.hibernate.engine;
import java.io.Serializable; import java.io.Serializable;
import org.jboss.logging.Logger;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.HibernateLogger; import org.hibernate.HibernateLogger;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
import org.hibernate.cache.CacheKey; import org.hibernate.cache.CacheKey;
import org.hibernate.cache.entry.CacheEntry; import org.hibernate.cache.entry.CacheEntry;
import org.hibernate.event.PostLoadEvent; import org.hibernate.event.PostLoadEvent;
import org.hibernate.event.PostLoadEventListener; import org.hibernate.event.PostLoadEventListener;
import org.hibernate.event.PreLoadEvent; import org.hibernate.event.PreLoadEvent;
import org.hibernate.event.PreLoadEventListener; import org.hibernate.event.PreLoadEventListener;
import org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.BackrefPropertyAccessor; import org.hibernate.property.BackrefPropertyAccessor;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.type.TypeHelper; import org.hibernate.type.TypeHelper;
import org.jboss.logging.Logger;
/** /**
* Functionality relating to Hibernate's two-phase loading process, * Functionality relating to Hibernate's two-phase loading process,
@ -161,13 +164,7 @@ public final class TwoPhaseLoad {
session, session,
entity entity
); );
CacheKey cacheKey = new CacheKey( CacheKey cacheKey = session.generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
id,
persister.getIdentifierType(),
persister.getRootEntityName(),
session.getEntityMode(),
session.getFactory()
);
// explicit handling of caching for rows just inserted and then somehow forced to be read // explicit handling of caching for rows just inserted and then somehow forced to be read
// from the database *within the same transaction*. usually this is done by // from the database *within the same transaction*. usually this is done by

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-2011, 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.engine.loading; package org.hibernate.engine.loading;
import java.io.Serializable; import java.io.Serializable;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList; import java.util.ArrayList;
@ -30,6 +30,9 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.EntityMode; import org.hibernate.EntityMode;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -44,7 +47,6 @@ import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.Status; import org.hibernate.engine.Status;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.jboss.logging.Logger;
/** /**
* Represents state associated with the processing of a given {@link ResultSet} * Represents state associated with the processing of a given {@link ResultSet}
@ -313,13 +315,7 @@ public class CollectionLoadContext {
} }
CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister ); CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
CacheKey cacheKey = new CacheKey( CacheKey cacheKey = session.generateCacheKey( lce.getKey(), persister.getKeyType(), persister.getRole() );
lce.getKey(),
persister.getKeyType(),
persister.getRole(),
session.getEntityMode(),
session.getFactory()
);
boolean put = persister.getCacheAccessStrategy().putFromLoad( boolean put = persister.getCacheAccessStrategy().putFromLoad(
cacheKey, cacheKey,
persister.getCacheEntryStructure().structure(entry), persister.getCacheEntryStructure().structure(entry),

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-2011, 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,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.event.def; package org.hibernate.event.def;
import org.jboss.logging.Logger;
import org.hibernate.HibernateLogger; import org.hibernate.HibernateLogger;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
@ -34,7 +36,6 @@ import org.hibernate.engine.Status;
import org.hibernate.event.EventSource; import org.hibernate.event.EventSource;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.jboss.logging.Logger;
/** /**
* A convenience base class for listeners that respond to requests to perform a * A convenience base class for listeners that respond to requests to perform a
@ -79,13 +80,7 @@ public class AbstractLockUpgradeEventListener extends AbstractReassociateEventLi
final SoftLock lock; final SoftLock lock;
final CacheKey ck; final CacheKey ck;
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
ck = new CacheKey( ck = source.generateCacheKey( entry.getId(), persister.getIdentifierType(), persister.getRootEntityName() );
entry.getId(),
persister.getIdentifierType(),
persister.getRootEntityName(),
source.getEntityMode(),
source.getFactory()
);
lock = persister.getCacheAccessStrategy().lockItem( ck, entry.getVersion() ); lock = persister.getCacheAccessStrategy().lockItem( ck, entry.getVersion() );
} }
else { else {

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-2011, 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,10 +20,13 @@
* 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.event.def; package org.hibernate.event.def;
import java.io.Serializable; import java.io.Serializable;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.HibernateLogger; import org.hibernate.HibernateLogger;
import org.hibernate.cache.CacheKey; import org.hibernate.cache.CacheKey;
@ -37,7 +40,6 @@ import org.hibernate.event.InitializeCollectionEvent;
import org.hibernate.event.InitializeCollectionEventListener; import org.hibernate.event.InitializeCollectionEventListener;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.jboss.logging.Logger;
/** /**
* @author Gavin King * @author Gavin King
@ -115,23 +117,24 @@ public class DefaultInitializeCollectionEventListener implements InitializeColle
final SessionFactoryImplementor factory = source.getFactory(); final SessionFactoryImplementor factory = source.getFactory();
final CacheKey ck = new CacheKey(id, persister.getKeyType(), persister.getRole(), source.getEntityMode(), final CacheKey ck = source.generateCacheKey( id, persister.getKeyType(), persister.getRole() );
source.getFactory());
Object ce = persister.getCacheAccessStrategy().get(ck, source.getTimestamp()); Object ce = persister.getCacheAccessStrategy().get(ck, source.getTimestamp());
if (factory.getStatistics().isStatisticsEnabled()) { if ( factory.getStatistics().isStatisticsEnabled() ) {
if (ce == null) { if (ce == null) {
factory.getStatisticsImplementor().secondLevelCacheMiss(persister.getCacheAccessStrategy().getRegion().getName()); factory.getStatisticsImplementor()
} else { .secondLevelCacheMiss( persister.getCacheAccessStrategy().getRegion().getName() );
factory.getStatisticsImplementor().secondLevelCacheHit(persister.getCacheAccessStrategy().getRegion().getName() }
); else {
factory.getStatisticsImplementor()
.secondLevelCacheHit( persister.getCacheAccessStrategy().getRegion().getName() );
}
} }
if ( ce == null ) {
return false;
} }
if (ce == null) return false;
CollectionCacheEntry cacheEntry = (CollectionCacheEntry)persister.getCacheEntryStructure().destructure(ce, factory); CollectionCacheEntry cacheEntry = (CollectionCacheEntry)persister.getCacheEntryStructure().destructure(ce, factory);
final PersistenceContext persistenceContext = source.getPersistenceContext(); final PersistenceContext persistenceContext = source.getPersistenceContext();

View File

@ -351,12 +351,10 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
SoftLock lock = null; SoftLock lock = null;
final CacheKey ck; final CacheKey ck;
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
ck = new CacheKey( ck = source.generateCacheKey(
event.getEntityId(), event.getEntityId(),
persister.getIdentifierType(), persister.getIdentifierType(),
persister.getRootEntityName(), persister.getRootEntityName()
source.getEntityMode(),
source.getFactory()
); );
lock = persister.getCacheAccessStrategy().lockItem( ck, null ); lock = persister.getCacheAccessStrategy().lockItem( ck, null );
} }
@ -535,12 +533,10 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
final SessionFactoryImplementor factory = source.getFactory(); final SessionFactoryImplementor factory = source.getFactory();
final CacheKey ck = new CacheKey( final CacheKey ck = source.generateCacheKey(
event.getEntityId(), event.getEntityId(),
persister.getIdentifierType(), persister.getIdentifierType(),
persister.getRootEntityName(), persister.getRootEntityName()
source.getEntityMode(),
source.getFactory()
); );
Object ce = persister.getCacheAccessStrategy().get( ck, source.getTimestamp() ); Object ce = persister.getCacheAccessStrategy().get( ck, source.getTimestamp() );
if ( factory.getStatistics().isStatisticsEnabled() ) { if ( factory.getStatistics().isStatisticsEnabled() ) {

View File

@ -127,12 +127,10 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
} }
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
final CacheKey ck = new CacheKey( final CacheKey ck = source.generateCacheKey(
id, id,
persister.getIdentifierType(), persister.getIdentifierType(),
persister.getRootEntityName(), persister.getRootEntityName()
source.getEntityMode(),
source.getFactory()
); );
persister.getCacheAccessStrategy().evict( ck ); persister.getCacheAccessStrategy().evict( ck );
} }

View File

@ -36,6 +36,7 @@ import org.hibernate.SQLQuery;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.SessionException; import org.hibernate.SessionException;
import org.hibernate.SharedSessionContract; import org.hibernate.SharedSessionContract;
import org.hibernate.cache.CacheKey;
import org.hibernate.engine.EntityKey; import org.hibernate.engine.EntityKey;
import org.hibernate.engine.NamedQueryDefinition; import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.engine.NamedSQLQueryDefinition; import org.hibernate.engine.NamedSQLQueryDefinition;
@ -54,6 +55,7 @@ import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider; import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.type.Type;
/** /**
* Functionality common to stateless and stateful sessions * Functionality common to stateless and stateful sessions
@ -234,6 +236,11 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSession
return new EntityKey( id, persister, getEntityMode(), getTenantIdentifier() ); return new EntityKey( id, persister, getEntityMode(), getTenantIdentifier() );
} }
@Override
public CacheKey generateCacheKey(Serializable id, Type type, String entityOrRoleName) {
return new CacheKey( id, type, entityOrRoleName, getEntityMode(), getTenantIdentifier(), getFactory() );
}
private transient JdbcConnectionAccess jdbcConnectionAccess; private transient JdbcConnectionAccess jdbcConnectionAccess;
@Override @Override

View File

@ -23,6 +23,9 @@
*/ */
package org.hibernate.impl; package org.hibernate.impl;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import java.io.IOException; import java.io.IOException;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
@ -41,9 +44,9 @@ import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import javax.naming.NamingException;
import javax.naming.Reference; import org.jboss.logging.Logger;
import javax.naming.StringRefAddr;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.Cache; import org.hibernate.Cache;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
@ -53,7 +56,6 @@ import org.hibernate.HibernateException;
import org.hibernate.HibernateLogger; import org.hibernate.HibernateLogger;
import org.hibernate.Interceptor; import org.hibernate.Interceptor;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.ObjectNotFoundException; import org.hibernate.ObjectNotFoundException;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.Session; import org.hibernate.Session;
@ -119,8 +121,8 @@ import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.jta.platform.spi.JtaPlatform; import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistryFactory; import org.hibernate.service.spi.SessionFactoryServiceRegistryFactory;
import org.hibernate.stat.internal.ConcurrentStatisticsImpl;
import org.hibernate.stat.Statistics; import org.hibernate.stat.Statistics;
import org.hibernate.stat.internal.ConcurrentStatisticsImpl;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.hbm2ddl.SchemaUpdate;
@ -129,7 +131,6 @@ import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver; import org.hibernate.type.TypeResolver;
import org.jboss.logging.Logger;
/** /**
@ -1006,7 +1007,8 @@ public final class SessionFactoryImpl
identifier, identifier,
p.getIdentifierType(), p.getIdentifierType(),
p.getRootEntityName(), p.getRootEntityName(),
EntityMode.POJO, EntityMode.POJO, // we have to assume POJO
null, // and also assume non tenancy
SessionFactoryImpl.this SessionFactoryImpl.this
); );
} }
@ -1051,7 +1053,8 @@ public final class SessionFactoryImpl
ownerIdentifier, ownerIdentifier,
p.getKeyType(), p.getKeyType(),
p.getRole(), p.getRole(),
EntityMode.POJO, EntityMode.POJO, // we have to assume POJO
null, // and also assume non tenancy
SessionFactoryImpl.this SessionFactoryImpl.this
); );
} }

View File

@ -42,6 +42,9 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jboss.logging.Logger;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.ConnectionReleaseMode; import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Criteria; import org.hibernate.Criteria;
@ -122,10 +125,10 @@ import org.hibernate.event.ReplicateEventListener;
import org.hibernate.event.SaveOrUpdateEvent; import org.hibernate.event.SaveOrUpdateEvent;
import org.hibernate.event.SaveOrUpdateEventListener; import org.hibernate.event.SaveOrUpdateEventListener;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.jdbc.ReturningWork; import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work; import org.hibernate.jdbc.Work;
import org.hibernate.jdbc.WorkExecutor; import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.loader.criteria.CriteriaLoader; import org.hibernate.loader.criteria.CriteriaLoader;
import org.hibernate.loader.custom.CustomLoader; import org.hibernate.loader.custom.CustomLoader;
import org.hibernate.loader.custom.CustomQuery; import org.hibernate.loader.custom.CustomQuery;
@ -139,7 +142,6 @@ import org.hibernate.stat.SessionStatistics;
import org.hibernate.stat.internal.SessionStatisticsImpl; import org.hibernate.stat.internal.SessionStatisticsImpl;
import org.hibernate.type.SerializationException; import org.hibernate.type.SerializationException;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.jboss.logging.Logger;
/** /**
* Concrete implementation of a Session. * Concrete implementation of a Session.
@ -155,10 +157,7 @@ import org.jboss.logging.Logger;
*/ */
public final class SessionImpl public final class SessionImpl
extends AbstractSessionImpl extends AbstractSessionImpl
implements EventSource, implements EventSource, org.hibernate.Session, TransactionContext, LobCreationContext {
org.hibernate.Session,
TransactionContext,
LobCreationContext {
// todo : need to find a clean way to handle the "event source" role // todo : need to find a clean way to handle the "event source" role
// a separate class responsible for generating/dispatching events just duplicates most of the Session methods... // a separate class responsible for generating/dispatching events just duplicates most of the Session methods...

View File

@ -227,13 +227,7 @@ public class StatelessSessionImpl extends AbstractSessionImpl implements Statele
// } // }
if ( persister.hasCache() ) { if ( persister.hasCache() ) {
final CacheKey ck = new CacheKey( final CacheKey ck = generateCacheKey( id, persister.getIdentifierType(), persister.getRootEntityName() );
id,
persister.getIdentifierType(),
persister.getRootEntityName(),
this.getEntityMode(),
this.getFactory()
);
persister.getCacheAccessStrategy().evict( ck ); persister.getCacheAccessStrategy().evict( ck );
} }

View File

@ -807,11 +807,16 @@ public abstract class AbstractEntityPersister
throw new HibernateException( "entity is not associated with the session: " + id ); throw new HibernateException( "entity is not associated with the session: " + id );
} }
if (LOG.isTraceEnabled()) LOG.trace("Initializing lazy properties of: " + MessageHelper.infoString(this, id, getFactory()) if ( LOG.isTraceEnabled() ) {
+ ", field access: " + fieldName); LOG.trace(
"Initializing lazy properties of: " +
MessageHelper.infoString( this, id, getFactory() ) +
", field access: " + fieldName
);
}
if ( hasCache() ) { if ( hasCache() ) {
CacheKey cacheKey = new CacheKey(id, getIdentifierType(), getEntityName(), session.getEntityMode(), getFactory() ); CacheKey cacheKey = session.generateCacheKey( id, getIdentifierType(), getEntityName() );
Object ce = getCacheAccessStrategy().get( cacheKey, session.getTimestamp() ); Object ce = getCacheAccessStrategy().get( cacheKey, session.getTimestamp() );
if (ce!=null) { if (ce!=null) {
CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure(ce, factory); CacheEntry cacheEntry = (CacheEntry) getCacheEntryStructure().destructure(ce, factory);
@ -3574,13 +3579,7 @@ public abstract class AbstractEntityPersister
// check to see if it is in the second-level cache // check to see if it is in the second-level cache
if ( hasCache() ) { if ( hasCache() ) {
CacheKey ck = new CacheKey( CacheKey ck = session.generateCacheKey( id, getIdentifierType(), getRootEntityName() );
id,
getIdentifierType(),
getRootEntityName(),
session.getEntityMode(),
session.getFactory()
);
if ( getCacheAccessStrategy().get( ck, session.getTimestamp() ) != null ) { if ( getCacheAccessStrategy().get( ck, session.getTimestamp() ) != null ) {
return Boolean.FALSE; return Boolean.FALSE;
} }

View File

@ -112,8 +112,12 @@ public class DynamicFilterTest extends BaseCoreFunctionalTestCase {
Hibernate.initialize( sp.getOrders() ); Hibernate.initialize( sp.getOrders() );
CollectionPersister persister = sessionFactory().getCollectionPersister( Salesperson.class.getName() + ".orders" ); CollectionPersister persister = sessionFactory().getCollectionPersister( Salesperson.class.getName() + ".orders" );
assertTrue( "No cache for collection", persister.hasCache() ); assertTrue( "No cache for collection", persister.hasCache() );
CollectionCacheEntry cachedData = ( CollectionCacheEntry ) persister.getCacheAccessStrategy() CacheKey cacheKey = ( (SessionImplementor) session ).generateCacheKey(
.get( new CacheKey( testData.steveId, persister.getKeyType(), persister.getRole(), EntityMode.POJO, sessionFactory() ), ts ); testData.steveId,
persister.getKeyType(),
persister.getRole()
);
CollectionCacheEntry cachedData = ( CollectionCacheEntry ) persister.getCacheAccessStrategy().get( cacheKey, ts );
assertNotNull( "collection was not in cache", cachedData ); assertNotNull( "collection was not in cache", cachedData );
session.close(); session.close();
@ -126,8 +130,12 @@ public class DynamicFilterTest extends BaseCoreFunctionalTestCase {
.uniqueResult(); .uniqueResult();
assertEquals( "Filtered-collection not bypassing 2L-cache", 1, sp.getOrders().size() ); assertEquals( "Filtered-collection not bypassing 2L-cache", 1, sp.getOrders().size() );
CollectionCacheEntry cachedData2 = ( CollectionCacheEntry ) persister.getCacheAccessStrategy() CacheKey cacheKey2 = ( (SessionImplementor) session ).generateCacheKey(
.get( new CacheKey( testData.steveId, persister.getKeyType(), persister.getRole(), EntityMode.POJO, sessionFactory() ), ts ); testData.steveId,
persister.getKeyType(),
persister.getRole()
);
CollectionCacheEntry cachedData2 = ( CollectionCacheEntry ) persister.getCacheAccessStrategy().get( cacheKey2, ts );
assertNotNull( "collection no longer in cache!", cachedData2 ); assertNotNull( "collection no longer in cache!", cachedData2 );
assertSame( "Different cache values!", cachedData, cachedData2 ); assertSame( "Different cache values!", cachedData, cachedData2 );

View File

@ -24,7 +24,6 @@
package org.hibernate.test.multitenancy.schema; package org.hibernate.test.multitenancy.schema;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/** /**
@ -38,12 +37,12 @@ public class Customer {
public Customer() { public Customer() {
} }
public Customer(String name) { public Customer(Long id, String name) {
this.id = id;
this.name = name; this.name = name;
} }
@Id @Id
@GeneratedValue
public Long getId() { public Long getId() {
return id; return id;
} }

View File

@ -30,8 +30,12 @@ import org.hibernate.HibernateException;
import org.hibernate.MultiTenancyStrategy; import org.hibernate.MultiTenancyStrategy;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.cache.HashtableCacheProvider;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import org.hibernate.service.internal.BasicServiceRegistryImpl; import org.hibernate.service.internal.BasicServiceRegistryImpl;
import org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl; import org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
import org.hibernate.service.jdbc.connections.spi.AbstractMultiTenantConnectionProvider; import org.hibernate.service.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
@ -58,7 +62,7 @@ public class SchemaBasedMultiTenancyTest extends BaseUnitTestCase {
private ServiceRegistryImplementor serviceRegistry; private ServiceRegistryImplementor serviceRegistry;
private SessionFactory sessionFactory; private SessionFactoryImplementor sessionFactory;
@Before @Before
public void setUp() { public void setUp() {
@ -84,9 +88,13 @@ public class SchemaBasedMultiTenancyTest extends BaseUnitTestCase {
Configuration cfg = new Configuration(); Configuration cfg = new Configuration();
cfg.getProperties().put( Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE ); cfg.getProperties().put( Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE );
cfg.setProperty( Environment.CACHE_PROVIDER, HashtableCacheProvider.class.getName() );
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
cfg.addAnnotatedClass( Customer.class ); cfg.addAnnotatedClass( Customer.class );
cfg.buildMappings(); cfg.buildMappings();
RootClass meta = (RootClass) cfg.getClassMapping( Customer.class.getName() );
meta.setCacheConcurrencyStrategy( "read-write" );
// do the acme export // do the acme export
new SchemaExport( new SchemaExport(
@ -147,7 +155,7 @@ public class SchemaBasedMultiTenancyTest extends BaseUnitTestCase {
serviceRegistry = new BasicServiceRegistryImpl( cfg.getProperties() ); serviceRegistry = new BasicServiceRegistryImpl( cfg.getProperties() );
serviceRegistry.registerService( MultiTenantConnectionProvider.class, multiTenantConnectionProvider ); serviceRegistry.registerService( MultiTenantConnectionProvider.class, multiTenantConnectionProvider );
sessionFactory = cfg.buildSessionFactory( serviceRegistry ); sessionFactory = (SessionFactoryImplementor) cfg.buildSessionFactory( serviceRegistry );
} }
@After @After
@ -175,7 +183,7 @@ public class SchemaBasedMultiTenancyTest extends BaseUnitTestCase {
Session session = openSession(); Session session = openSession();
session.setTenantIdentifier( "jboss" ); session.setTenantIdentifier( "jboss" );
session.beginTransaction(); session.beginTransaction();
Customer steve = new Customer( "steve" ); Customer steve = new Customer( 1L, "steve" );
session.save( steve ); session.save( steve );
session.getTransaction().commit(); session.getTransaction().commit();
session.close(); session.close();
@ -200,4 +208,97 @@ public class SchemaBasedMultiTenancyTest extends BaseUnitTestCase {
session.close(); session.close();
} }
@Test
public void testSameIdentifiers() {
// create a customer 'steve' in jboss
Session session = openSession();
session.setTenantIdentifier( "jboss" );
session.beginTransaction();
Customer steve = new Customer( 1L, "steve" );
session.save( steve );
session.getTransaction().commit();
session.close();
// now, create a customer 'john' in acme
session = openSession();
session.setTenantIdentifier( "acme" );
session.beginTransaction();
Customer john = new Customer( 1L, "john" );
session.save( john );
session.getTransaction().commit();
session.close();
sessionFactory.getStatisticsImplementor().clear();
// make sure we get the correct people back, from cache
// first, jboss
{
session = openSession();
session.setTenantIdentifier( "jboss" );
session.beginTransaction();
Customer customer = (Customer) session.load( Customer.class, 1L );
Assert.assertEquals( "steve", customer.getName() );
// also, make sure this came from second level
Assert.assertEquals( 1, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() );
session.getTransaction().commit();
session.close();
}
sessionFactory.getStatisticsImplementor().clear();
// then, acme
{
session = openSession();
session.setTenantIdentifier( "acme" );
session.beginTransaction();
Customer customer = (Customer) session.load( Customer.class, 1L );
Assert.assertEquals( "john", customer.getName() );
// also, make sure this came from second level
Assert.assertEquals( 1, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() );
session.getTransaction().commit();
session.close();
}
// make sure the same works from datastore too
sessionFactory.getStatisticsImplementor().clear();
sessionFactory.getCache().evictEntityRegions();
// first jboss
{
session = openSession();
session.setTenantIdentifier( "jboss" );
session.beginTransaction();
Customer customer = (Customer) session.load( Customer.class, 1L );
Assert.assertEquals( "steve", customer.getName() );
// also, make sure this came from second level
Assert.assertEquals( 0, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() );
session.getTransaction().commit();
session.close();
}
sessionFactory.getStatisticsImplementor().clear();
// then, acme
{
session = openSession();
session.setTenantIdentifier( "acme" );
session.beginTransaction();
Customer customer = (Customer) session.load( Customer.class, 1L );
Assert.assertEquals( "john", customer.getName() );
// also, make sure this came from second level
Assert.assertEquals( 0, sessionFactory.getStatisticsImplementor().getSecondLevelCacheHitCount() );
session.getTransaction().commit();
session.close();
}
session = openSession();
session.setTenantIdentifier( "jboss" );
session.beginTransaction();
session.delete( steve );
session.getTransaction().commit();
session.close();
session = openSession();
session.setTenantIdentifier( "acme" );
session.beginTransaction();
session.delete( john );
session.getTransaction().commit();
session.close();
}
} }

View File

@ -37,6 +37,7 @@ import org.hibernate.Interceptor;
import org.hibernate.Query; import org.hibernate.Query;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.cache.CacheKey;
import org.hibernate.collection.PersistentCollection; import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.EntityKey; import org.hibernate.engine.EntityKey;
import org.hibernate.engine.LoadQueryInfluencers; import org.hibernate.engine.LoadQueryInfluencers;
@ -88,6 +89,11 @@ public abstract class AbstractDelegateSessionImplementor implements SessionImple
return delegate.generateEntityKey( id, persister ); return delegate.generateEntityKey( id, persister );
} }
@Override
public CacheKey generateCacheKey(Serializable id, Type type, String entityOrRoleName) {
return delegate.generateCacheKey( id, type, entityOrRoleName );
}
@Override @Override
public <T> T execute(Callback<T> callback) { public <T> T execute(Callback<T> callback) {
return delegate.execute( callback ); return delegate.execute( callback );