/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007-2011, 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 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
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.tm;
import javax.transaction.Transaction;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.EntityMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.criterion.Order;
import org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory;
import org.junit.Test;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.jta.TestingJtaBootstrap;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
/**
* @author Gavin King
*/
public class CMTTest extends BaseCoreFunctionalTestCase {
@Override
public String[] getMappings() {
return new String[] { "tm/Item.hbm.xml" };
}
@Override
public void configure(Configuration cfg) {
TestingJtaBootstrap.prepare( cfg.getProperties() );
cfg.setProperty( Environment.TRANSACTION_STRATEGY, CMTTransactionFactory.class.getName() );
cfg.setProperty( Environment.AUTO_CLOSE_SESSION, "true" );
cfg.setProperty( Environment.FLUSH_BEFORE_COMPLETION, "true" );
cfg.setProperty( Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.AFTER_STATEMENT.toString() );
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
cfg.setProperty( Environment.DEFAULT_ENTITY_MODE, EntityMode.MAP.toString() );
}
@Override
public String getCacheConcurrencyStrategy() {
return "transactional";
}
@Test
public void testConcurrent() throws Exception {
sessionFactory().getStatistics().clear();
assertEquals( 0, sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount() );
assertEquals( 0, sessionFactory().getStatistics().getUpdateTimestampsCachePutCount() );
assertEquals( 0, sessionFactory().getStatistics().getUpdateTimestampsCacheMissCount() );
assertNotNull( sessionFactory().getEntityPersister( "Item" ).getCacheAccessStrategy() );
assertEquals( 0, sessionFactory().getStatistics().getEntityLoadCount() );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s = openSession();
Map foo = new HashMap();
foo.put( "name", "Foo" );
foo.put( "description", "a big foo" );
s.persist( "Item", foo );
Map bar = new HashMap();
bar.put( "name", "Bar" );
bar.put( "description", "a small bar" );
s.persist( "Item", bar );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals(0, sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount());
assertEquals(3, sessionFactory().getStatistics().getUpdateTimestampsCachePutCount()); // Twice preinvalidate & one invalidate
assertEquals(0, sessionFactory().getStatistics().getUpdateTimestampsCacheMissCount());
sessionFactory().getCache().evictEntityRegion( "Item" );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s1 = openSession();
foo = ( Map ) s1.get( "Item", "Foo" );
//foo.put("description", "a big red foo");
//s1.flush();
Transaction tx = TestingJtaBootstrap.INSTANCE.getTransactionManager().suspend();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s2 = openSession();
foo = ( Map ) s2.get( "Item", "Foo" );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
TestingJtaBootstrap.INSTANCE.getTransactionManager().resume( tx );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
sessionFactory().getCache().evictEntityRegion( "Item" );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s1 = openSession();
s1.createCriteria( "Item" ).list();
//foo.put("description", "a big red foo");
//s1.flush();
tx = TestingJtaBootstrap.INSTANCE.getTransactionManager().suspend();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s2 = openSession();
s2.createCriteria( "Item" ).list();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
TestingJtaBootstrap.INSTANCE.getTransactionManager().resume( tx );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s2 = openSession();
s2.createCriteria( "Item" ).list();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( 7, sessionFactory().getStatistics().getEntityLoadCount() );
assertEquals( 0, sessionFactory().getStatistics().getEntityFetchCount() );
assertEquals( 3, sessionFactory().getStatistics().getQueryExecutionCount() );
assertEquals( 0, sessionFactory().getStatistics().getQueryCacheHitCount() );
assertEquals( 0, sessionFactory().getStatistics().getQueryCacheMissCount() );
assertEquals( 0, sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount() );
assertEquals( 3, sessionFactory().getStatistics().getUpdateTimestampsCachePutCount() );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
s.createQuery( "delete from Item" ).executeUpdate();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
}
@Test
public void testConcurrentCachedQueries() throws Exception {
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s = openSession();
Map foo = new HashMap();
foo.put( "name", "Foo" );
foo.put( "description", "a big foo" );
s.persist( "Item", foo );
Map bar = new HashMap();
bar.put( "name", "Bar" );
bar.put( "description", "a small bar" );
s.persist( "Item", bar );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
synchronized ( this ) {
wait( 1000 );
}
sessionFactory().getStatistics().clear();
sessionFactory().getCache().evictEntityRegion( "Item" );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s4 = openSession();
Transaction tx4 = TestingJtaBootstrap.INSTANCE.getTransactionManager().suspend();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s1 = openSession();
List r1 = s1.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
assertEquals( r1.size(), 2 );
Transaction tx1 = TestingJtaBootstrap.INSTANCE.getTransactionManager().suspend();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s2 = openSession();
List r2 = s2.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
assertEquals( r2.size(), 2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheHitCount(), 2 );
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheMissCount(), 0 );
assertEquals( sessionFactory().getStatistics().getEntityLoadCount(), 2 );
assertEquals( sessionFactory().getStatistics().getEntityFetchCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCachePutCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCacheHitCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCacheMissCount(), 1 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount(), 1 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCachePutCount(), 0 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().resume( tx1 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s3 = openSession();
s3.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheHitCount(), 4 );
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheMissCount(), 0 );
assertEquals( sessionFactory().getStatistics().getEntityLoadCount(), 2 );
assertEquals( sessionFactory().getStatistics().getEntityFetchCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCachePutCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCacheHitCount(), 2 );
assertEquals( sessionFactory().getStatistics().getQueryCacheMissCount(), 1 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount(), 2 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCachePutCount(), 0 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheMissCount(), 0 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().resume( tx4 );
List r4 = s4.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
assertEquals( r4.size(), 2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheHitCount(), 6 );
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheMissCount(), 0 );
assertEquals( sessionFactory().getStatistics().getEntityLoadCount(), 2 );
assertEquals( sessionFactory().getStatistics().getEntityFetchCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCachePutCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCacheHitCount(), 3 );
assertEquals( sessionFactory().getStatistics().getQueryCacheMissCount(), 1 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount(), 3 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCachePutCount(), 0 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
s.createQuery( "delete from Item" ).executeUpdate();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
}
@Test
@RequiresDialectFeature(
value = DialectChecks.DoesReadCommittedNotCauseWritersToBlockReadersCheck.class,
comment = "write locks block readers"
)
public void testConcurrentCachedDirtyQueries() throws Exception {
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s = openSession();
Map foo = new HashMap();
foo.put( "name", "Foo" );
foo.put( "description", "a big foo" );
s.persist( "Item", foo );
Map bar = new HashMap();
bar.put( "name", "Bar" );
bar.put( "description", "a small bar" );
s.persist( "Item", bar );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
synchronized ( this ) {
wait( 1000 );
}
sessionFactory().getStatistics().clear();
sessionFactory().getCache().evictEntityRegion( "Item" );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s4 = openSession();
Transaction tx4 = TestingJtaBootstrap.INSTANCE.getTransactionManager().suspend();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s1 = openSession();
List r1 = s1.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
assertEquals( r1.size(), 2 );
foo = ( Map ) r1.get( 0 );
foo.put( "description", "a big red foo" );
s1.flush();
Transaction tx1 = TestingJtaBootstrap.INSTANCE.getTransactionManager().suspend();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s2 = openSession();
List r2 = s2.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
assertEquals( r2.size(), 2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheHitCount(), 0 );
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheMissCount(), 0 );
assertEquals( sessionFactory().getStatistics().getEntityLoadCount(), 4 );
assertEquals( sessionFactory().getStatistics().getEntityFetchCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryExecutionCount(), 2 );
assertEquals( sessionFactory().getStatistics().getQueryCachePutCount(), 2 );
assertEquals( sessionFactory().getStatistics().getQueryCacheHitCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryCacheMissCount(), 2 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount(), 4 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCachePutCount(), 2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().resume( tx1 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCachePutCount(), 3 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount(), 5 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s3 = openSession();
s3.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheHitCount(), 0 );
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheMissCount(), 0 );
assertEquals( sessionFactory().getStatistics().getEntityLoadCount(), 6 );
assertEquals( sessionFactory().getStatistics().getEntityFetchCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryExecutionCount(), 3 );
assertEquals( sessionFactory().getStatistics().getQueryCachePutCount(), 3 );
assertEquals( sessionFactory().getStatistics().getQueryCacheHitCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryCacheMissCount(), 3 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount(), 6 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().resume( tx4 );
List r4 = s4.createCriteria( "Item" ).addOrder( Order.asc( "description" ) )
.setCacheable( true ).list();
assertEquals( r4.size(), 2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheHitCount(), 2 );
assertEquals( sessionFactory().getStatistics().getSecondLevelCacheMissCount(), 0 );
assertEquals( sessionFactory().getStatistics().getEntityLoadCount(), 6 );
assertEquals( sessionFactory().getStatistics().getEntityFetchCount(), 0 );
assertEquals( sessionFactory().getStatistics().getQueryExecutionCount(), 3 );
assertEquals( sessionFactory().getStatistics().getQueryCachePutCount(), 3 );
assertEquals( sessionFactory().getStatistics().getQueryCacheHitCount(), 1 );
assertEquals( sessionFactory().getStatistics().getQueryCacheMissCount(), 3 );
assertEquals( sessionFactory().getStatistics().getUpdateTimestampsCacheHitCount(), 7 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
s.createQuery( "delete from Item" ).executeUpdate();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
}
@Test
public void testCMT() throws Exception {
sessionFactory().getStatistics().clear();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s = openSession();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertFalse( s.isOpen() );
assertEquals( sessionFactory().getStatistics().getFlushCount(), 0 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
TestingJtaBootstrap.INSTANCE.getTransactionManager().rollback();
assertFalse( s.isOpen() );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
Map item = new HashMap();
item.put( "name", "The Item" );
item.put( "description", "The only item we have" );
s.persist( "Item", item );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertFalse( s.isOpen() );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
item = ( Map ) s.createQuery( "from Item" ).uniqueResult();
assertNotNull( item );
s.delete( item );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertFalse( s.isOpen() );
assertEquals( sessionFactory().getStatistics().getTransactionCount(), 4 );
assertEquals( sessionFactory().getStatistics().getSuccessfulTransactionCount(), 3 );
assertEquals( sessionFactory().getStatistics().getEntityDeleteCount(), 1 );
assertEquals( sessionFactory().getStatistics().getEntityInsertCount(), 1 );
assertEquals( sessionFactory().getStatistics().getSessionOpenCount(), 4 );
assertEquals( sessionFactory().getStatistics().getSessionCloseCount(), 4 );
assertEquals( sessionFactory().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( sessionFactory().getStatistics().getFlushCount(), 2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
s.createQuery( "delete from Item" ).executeUpdate();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
}
@Test
public void testCurrentSession() throws Exception {
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s = sessionFactory().getCurrentSession();
Session s2 = sessionFactory().getCurrentSession();
assertSame( s, s2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
assertFalse( s.isOpen() );
// TODO : would be nice to automate-test that the SF internal map actually gets cleaned up
// i verified that is does currently in my debugger...
}
@Test
public void testCurrentSessionWithIterate() throws Exception {
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s = openSession();
Map item1 = new HashMap();
item1.put( "name", "Item - 1" );
item1.put( "description", "The first item" );
s.persist( "Item", item1 );
Map item2 = new HashMap();
item2.put( "name", "Item - 2" );
item2.put( "description", "The second item" );
s.persist( "Item", item2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
// First, test iterating the partial iterator; iterate to past
// the first, but not the second, item
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = sessionFactory().getCurrentSession();
Iterator itr = s.createQuery( "from Item" ).iterate();
if ( !itr.hasNext() ) {
fail( "No results in iterator" );
}
itr.next();
if ( !itr.hasNext() ) {
fail( "Only one result in iterator" );
}
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
// Next, iterate the entire result
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = sessionFactory().getCurrentSession();
itr = s.createQuery( "from Item" ).iterate();
if ( !itr.hasNext() ) {
fail( "No results in iterator" );
}
while ( itr.hasNext() ) {
itr.next();
}
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = openSession();
s.createQuery( "delete from Item" ).executeUpdate();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
}
@Test
public void testCurrentSessionWithScroll() throws Exception {
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
Session s = sessionFactory().getCurrentSession();
Map item1 = new HashMap();
item1.put( "name", "Item - 1" );
item1.put( "description", "The first item" );
s.persist( "Item", item1 );
Map item2 = new HashMap();
item2.put( "name", "Item - 2" );
item2.put( "description", "The second item" );
s.persist( "Item", item2 );
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
// First, test partially scrolling the result with out closing
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = sessionFactory().getCurrentSession();
ScrollableResults results = s.createQuery( "from Item" ).scroll();
results.next();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
// Next, test partially scrolling the result with closing
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = sessionFactory().getCurrentSession();
results = s.createQuery( "from Item" ).scroll();
results.next();
results.close();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
// Next, scroll the entire result (w/o closing)
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = sessionFactory().getCurrentSession();
results = s.createQuery( "from Item" ).scroll();
while ( results.next() ) {
// do nothing
}
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
// Next, scroll the entire result (closing)
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = sessionFactory().getCurrentSession();
results = s.createQuery( "from Item" ).scroll();
while ( results.next() ) {
// do nothing
}
results.close();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
TestingJtaBootstrap.INSTANCE.getTransactionManager().begin();
s = sessionFactory().getCurrentSession();
s.createQuery( "delete from Item" ).executeUpdate();
TestingJtaBootstrap.INSTANCE.getTransactionManager().commit();
}
}