Skip to content

Commit

Permalink
HHH-7097 Cache naturalId mapping on load event
Browse files Browse the repository at this point in the history
  • Loading branch information
edalquist committed Feb 21, 2012
1 parent 13f4c83 commit c0b66d5
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 117 deletions.
Expand Up @@ -43,6 +43,7 @@
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.spi.PersistenceContext.CachedNaturalIdValueSource;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EventType;
Expand Down Expand Up @@ -442,6 +443,22 @@ protected Object loadFromDatasource(
event.getLockOptions(),
source
);

if (entity != null && persister.hasNaturalIdentifier()) {
final int[] naturalIdentifierProperties = persister.getNaturalIdentifierProperties();
final Object[] naturalId = new Object[naturalIdentifierProperties.length];

for ( int i = 0; i < naturalIdentifierProperties.length; i++ ) {
naturalId[i] = persister.getPropertyValue( entity, naturalIdentifierProperties[i] );
}

event.getSession().getPersistenceContext().cacheNaturalIdResolution(
persister,
event.getEntityId(),
naturalId,
CachedNaturalIdValueSource.LOAD
);
}

if ( event.isAssociationFetch() && source.getFactory().getStatistics().isStatisticsEnabled() ) {
source.getFactory().getStatisticsImplementor().fetchEntity( event.getEntityClassName() );
Expand Down
Expand Up @@ -52,6 +52,13 @@
public class NaturalIdOnSingleManyToOneTest extends BaseCoreFunctionalTestCase {
private static final Logger log = Logger.getLogger( NaturalIdOnSingleManyToOneTest.class );

@Override
protected void cleanupTest() throws Exception {
this.cleanupCache();

this.deleteAllData();
}

@Test
public void testMappingProperties() {
log.warn("Commented out test");
Expand Down Expand Up @@ -109,37 +116,17 @@ public void testManyToOneNaturalIdCached() {
// first query
List results = criteria.list();
assertEquals( 1, results.size() );
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"First query should be a miss", 1, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query result should be added to cache", 1, stats
.getNaturalIdCachePutCount()
);
assertEquals(
"Query count should be one", 1, stats
.getNaturalIdQueryExecutionCount()
);
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() );

// query a second time - result should be in session cache
criteria.list();
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"Second query should not be a miss", 1, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query count should be one", 1, stats
.getNaturalIdQueryExecutionCount()
);
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() );

// cleanup
tx.rollback();
Expand Down
Expand Up @@ -48,6 +48,13 @@
*/
@SuppressWarnings("unchecked")
public class NaturalIdTest extends BaseCoreFunctionalTestCase {
@Override
protected void cleanupTest() throws Exception {
this.cleanupCache();

this.deleteAllData();
}

@Test
public void testMappingProperties() {
ClassMetadata metaData = sessionFactory().getClassMetadata(
Expand All @@ -67,12 +74,12 @@ public void testNaturalIdCached() {

Session s = openSession();
Transaction tx = s.beginTransaction();
State france = ( State ) s.load( State.class, 2 );
State france = this.getState( s, "Ile de France" );
Criteria criteria = s.createCriteria( Citizen.class );
criteria.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", france ) );
criteria.setCacheable( true );

s.getSessionFactory().getCache().evictNaturalIdRegions();
this.cleanupCache();

Statistics stats = sessionFactory().getStatistics();
stats.setStatisticsEnabled( true );
Expand All @@ -85,37 +92,17 @@ public void testNaturalIdCached() {
// first query
List results = criteria.list();
assertEquals( 1, results.size() );
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"First query should be a miss", 1, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query result should be added to cache", 1, stats
.getNaturalIdCachePutCount()
);
assertEquals(
"Query execution count should be one", 1, stats
.getNaturalIdQueryExecutionCount()
);
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() );

// query a second time - result should be cached in session
criteria.list();
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"Second query should not be a miss", 1, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query execution count should be one", 1, stats
.getNaturalIdQueryExecutionCount()
);
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() );

// cleanup
tx.rollback();
Expand All @@ -128,35 +115,27 @@ public void testNaturalIdLoaderNotCached() {

Session s = openSession();
Transaction tx = s.beginTransaction();
State france = ( State ) s.load( State.class, 2 );
State france = this.getState( s, "Ile de France" );
final NaturalIdLoadAccess naturalIdLoader = s.byNaturalId( Citizen.class );
naturalIdLoader.using( "ssn", "1234" ).using( "state", france );

//NaturalId cache gets populated during entity loading, need to clear it out
sessionFactory().getCache().evictNaturalIdRegions();
this.cleanupCache();
Statistics stats = sessionFactory().getStatistics();
stats.setStatisticsEnabled( true );
stats.clear();
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() );

// first query
Citizen citizen = (Citizen)naturalIdLoader.load();
assertNotNull( citizen );
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"First load should be a miss", 1, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query result should be added to cache", 1, stats
.getNaturalIdCachePutCount()
);
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 1, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 1, stats.getNaturalIdQueryExecutionCount() );

// cleanup
tx.rollback();
Expand All @@ -165,51 +144,88 @@ public void testNaturalIdLoaderNotCached() {

@Test
public void testNaturalIdLoaderCached() {
Statistics stats = sessionFactory().getStatistics();
stats.setStatisticsEnabled( true );
stats.clear();

assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 0, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() );

saveSomeCitizens();

Statistics stats = sessionFactory().getStatistics();
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"First load should be a miss", 1, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query result should be added to cache", 3, stats
.getNaturalIdCachePutCount()
);
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 2, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() );


//Try NaturalIdLoadAccess after insert

Session s = openSession();
Transaction tx = s.beginTransaction();
State france = ( State ) s.load( State.class, 2 );
final NaturalIdLoadAccess naturalIdLoader = s.byNaturalId( Citizen.class );
State france = this.getState( s, "Ile de France" );
NaturalIdLoadAccess naturalIdLoader = s.byNaturalId( Citizen.class );
naturalIdLoader.using( "ssn", "1234" ).using( "state", france );

//Not clearing naturalId caches, should be warm from entity loading
stats.setStatisticsEnabled( true );
stats.clear();
assertEquals(
"Cache hits should be empty", 0, stats
.getNaturalIdCacheHitCount()
);

// first query
Citizen citizen = (Citizen)naturalIdLoader.load();
assertNotNull( citizen );
assertEquals(
"Cache hits should be empty", 1, stats
.getNaturalIdCacheHitCount()
);
assertEquals(
"First load should be a miss", 0, stats
.getNaturalIdCacheMissCount()
);
assertEquals(
"Query result should be added to cache", 0, stats
.getNaturalIdCachePutCount()
);
assertEquals( "NaturalId Cache Hits", 1, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() );

// cleanup
tx.rollback();
s.close();


//Try NaturalIdLoadAccess

s = openSession();
tx = s.beginTransaction();

this.cleanupCache();
stats.setStatisticsEnabled( true );
stats.clear();

// first query
citizen = (Citizen) s.get( Citizen.class, citizen.getId() );
assertNotNull( citizen );
assertEquals( "NaturalId Cache Hits", 0, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() );

// cleanup
tx.rollback();
s.close();


//Try NaturalIdLoadAccess after load

s = openSession();
tx = s.beginTransaction();
france = this.getState( s, "Ile de France" );
naturalIdLoader = s.byNaturalId( Citizen.class );
naturalIdLoader.using( "ssn", "1234" ).using( "state", france );

//Not clearing naturalId caches, should be warm from entity loading
stats.setStatisticsEnabled( true );
stats.clear();

// first query
citizen = (Citizen)naturalIdLoader.load();
assertNotNull( citizen );
assertEquals( "NaturalId Cache Hits", 1, stats.getNaturalIdCacheHitCount() );
assertEquals( "NaturalId Cache Misses", 0, stats.getNaturalIdCacheMissCount() );
assertEquals( "NaturalId Cache Puts", 1, stats.getNaturalIdCachePutCount() );
assertEquals( "NaturalId Cache Queries", 0, stats.getNaturalIdQueryExecutionCount() );

// cleanup
tx.rollback();
Expand All @@ -222,7 +238,7 @@ public void testNaturalIdUncached() {

Session s = openSession();
Transaction tx = s.beginTransaction();
State france = ( State ) s.load( State.class, 2 );
State france = this.getState( s, "Ile de France" );
Criteria criteria = s.createCriteria( Citizen.class );
criteria.add(
Restrictions.naturalId().set( "ssn", "1234" ).set(
Expand All @@ -232,7 +248,7 @@ public void testNaturalIdUncached() {
);
criteria.setCacheable( false );

s.getSessionFactory().getCache().evictNaturalIdRegions();
this.cleanupCache();

Statistics stats = sessionFactory().getStatistics();
stats.setStatisticsEnabled( true );
Expand Down Expand Up @@ -310,6 +326,13 @@ private void saveSomeCitizens() {
s.close();
}

private State getState(Session s, String name) {
Criteria criteria = s.createCriteria( State.class );
criteria.add( Restrictions.eq( "name", name ) );
criteria.setCacheable( true );
return (State) criteria.list().get( 0 );
}

@Override
protected void configure(Configuration cfg) {
cfg.setProperty( "hibernate.cache.use_query_cache", "true" );
Expand Down

0 comments on commit c0b66d5

Please sign in to comment.