HHH-10649 - When 2LC enabled, flush session and then refresh entity cause dirty read in another session / transaction
This commit is contained in:
parent
a68a6c6770
commit
cbdab9d87f
|
@ -13,18 +13,22 @@ import java.util.Map;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.PersistentObjectException;
|
import org.hibernate.PersistentObjectException;
|
||||||
import org.hibernate.UnresolvableObjectException;
|
import org.hibernate.UnresolvableObjectException;
|
||||||
|
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
|
||||||
|
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
|
||||||
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
|
||||||
|
import org.hibernate.cache.spi.access.SoftLock;
|
||||||
import org.hibernate.engine.internal.Cascade;
|
import org.hibernate.engine.internal.Cascade;
|
||||||
import org.hibernate.engine.internal.CascadePoint;
|
import org.hibernate.engine.internal.CascadePoint;
|
||||||
import org.hibernate.engine.spi.CascadingActions;
|
import org.hibernate.engine.spi.CascadingActions;
|
||||||
import org.hibernate.engine.spi.EntityEntry;
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.event.spi.EventSource;
|
import org.hibernate.event.spi.EventSource;
|
||||||
import org.hibernate.event.spi.RefreshEvent;
|
import org.hibernate.event.spi.RefreshEvent;
|
||||||
import org.hibernate.event.spi.RefreshEventListener;
|
import org.hibernate.event.spi.RefreshEventListener;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
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.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
|
@ -136,17 +140,31 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( persister.hasCache() ) {
|
if ( persister.hasCache() ) {
|
||||||
|
Object previousVersion = null;
|
||||||
|
if ( persister.isVersionPropertyGenerated() ) {
|
||||||
|
// we need to grab the version value from the entity, otherwise
|
||||||
|
// we have issues with generated-version entities that may have
|
||||||
|
// multiple actions queued during the same flush
|
||||||
|
previousVersion = persister.getVersion( object );
|
||||||
|
}
|
||||||
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
final EntityRegionAccessStrategy cache = persister.getCacheAccessStrategy();
|
||||||
Object ck = cache.generateCacheKey(
|
final Object ck = cache.generateCacheKey(
|
||||||
id,
|
id,
|
||||||
persister,
|
persister,
|
||||||
source.getFactory(),
|
source.getFactory(),
|
||||||
source.getTenantIdentifier()
|
source.getTenantIdentifier()
|
||||||
);
|
);
|
||||||
cache.evict( ck );
|
final SoftLock lock = cache.lockItem( source, ck, previousVersion );
|
||||||
|
source.getActionQueue().registerProcess( new AfterTransactionCompletionProcess() {
|
||||||
|
@Override
|
||||||
|
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
|
||||||
|
cache.unlockItem( session, ck, lock );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
cache.remove( source, ck );
|
||||||
}
|
}
|
||||||
|
|
||||||
evictCachedCollections( persister, id, source.getFactory() );
|
evictCachedCollections( persister, id, source );
|
||||||
|
|
||||||
String previousFetchProfile = source.getLoadQueryInfluencers().getInternalFetchProfile();
|
String previousFetchProfile = source.getLoadQueryInfluencers().getInternalFetchProfile();
|
||||||
source.getLoadQueryInfluencers().setInternalFetchProfile( "refresh" );
|
source.getLoadQueryInfluencers().setInternalFetchProfile( "refresh" );
|
||||||
|
@ -168,19 +186,36 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void evictCachedCollections(EntityPersister persister, Serializable id, SessionFactoryImplementor factory) {
|
private void evictCachedCollections(EntityPersister persister, Serializable id, EventSource source) {
|
||||||
evictCachedCollections( persister.getPropertyTypes(), id, factory );
|
evictCachedCollections( persister.getPropertyTypes(), id, source );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void evictCachedCollections(Type[] types, Serializable id, SessionFactoryImplementor factory)
|
private void evictCachedCollections(Type[] types, Serializable id, EventSource source)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
for ( Type type : types ) {
|
for ( Type type : types ) {
|
||||||
if ( type.isCollectionType() ) {
|
if ( type.isCollectionType() ) {
|
||||||
factory.getCache().evictCollection( ( (CollectionType) type ).getRole(), id );
|
CollectionPersister collectionPersister = source.getFactory().getCollectionPersister( ( (CollectionType) type ).getRole() );
|
||||||
|
if ( collectionPersister.hasCache() ) {
|
||||||
|
final CollectionRegionAccessStrategy cache = collectionPersister.getCacheAccessStrategy();
|
||||||
|
final Object ck = cache.generateCacheKey(
|
||||||
|
id,
|
||||||
|
collectionPersister,
|
||||||
|
source.getFactory(),
|
||||||
|
source.getTenantIdentifier()
|
||||||
|
);
|
||||||
|
final SoftLock lock = cache.lockItem( source, ck, null );
|
||||||
|
source.getActionQueue().registerProcess( new AfterTransactionCompletionProcess() {
|
||||||
|
@Override
|
||||||
|
public void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
|
||||||
|
cache.unlockItem( session, ck, lock );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
cache.remove( source, ck );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ( type.isComponentType() ) {
|
else if ( type.isComponentType() ) {
|
||||||
CompositeType actype = (CompositeType) type;
|
CompositeType actype = (CompositeType) type;
|
||||||
evictCachedCollections( actype.getSubtypes(), id, factory );
|
evictCachedCollections( actype.getSubtypes(), id, source );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,14 @@ import org.junit.Test;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.persister.entity.Lockable;
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for handling of data just inserted during a transaction being read from the database
|
* Tests for handling of data just inserted during a transaction being read from the database
|
||||||
|
@ -164,7 +168,9 @@ public class InsertedDataTest extends BaseCoreFunctionalTestCase {
|
||||||
s.close();
|
s.close();
|
||||||
|
|
||||||
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
assertEquals( 0, cacheMap.size() );
|
assertEquals( 1, cacheMap.size() );
|
||||||
|
Object lock = cacheMap.values().iterator().next();
|
||||||
|
assertEquals( "org.hibernate.testing.cache.AbstractReadWriteAccessStrategy$Lock", lock.getClass().getName() );
|
||||||
|
|
||||||
s = openSession();
|
s = openSession();
|
||||||
s.beginTransaction();
|
s.beginTransaction();
|
||||||
|
|
345
hibernate-core/src/test/java/org/hibernate/test/cache/RefreshUpdatedDataTest.java
vendored
Normal file
345
hibernate-core/src/test/java/org/hibernate/test/cache/RefreshUpdatedDataTest.java
vendored
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Version;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.Cache;
|
||||||
|
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
|
||||||
|
import org.hibernate.testing.RequiresDialect;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zhenlei Huang
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-10649")
|
||||||
|
@RequiresDialect(value = {H2Dialect.class})
|
||||||
|
public class RefreshUpdatedDataTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
ReadWriteCacheableItem.class,
|
||||||
|
ReadWriteVersionedCacheableItem.class,
|
||||||
|
NonStrictReadWriteCacheableItem.class,
|
||||||
|
NonStrictReadWriteVersionedCacheableItem.class,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration cfg) {
|
||||||
|
super.configure( cfg );
|
||||||
|
Properties properties = Environment.getProperties();
|
||||||
|
if ( H2Dialect.class.getName().equals( properties.get( Environment.DIALECT ) ) ) {
|
||||||
|
cfg.setProperty( Environment.URL, "jdbc:h2:mem:db-mvcc;MVCC=true" );
|
||||||
|
}
|
||||||
|
cfg.setProperty( Environment.CACHE_REGION_PREFIX, "" );
|
||||||
|
cfg.setProperty( Environment.GENERATE_STATISTICS, "true" );
|
||||||
|
cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
|
||||||
|
cfg.setProperty( Environment.CACHE_PROVIDER_CONFIG, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAndFlushThenRefresh() {
|
||||||
|
// prepare data
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
|
||||||
|
final String BEFORE = "before";
|
||||||
|
|
||||||
|
ReadWriteCacheableItem readWriteCacheableItem = new ReadWriteCacheableItem( BEFORE );
|
||||||
|
readWriteCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
readWriteCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( readWriteCacheableItem );
|
||||||
|
|
||||||
|
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem = new ReadWriteVersionedCacheableItem( BEFORE );
|
||||||
|
readWriteVersionedCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
readWriteVersionedCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( readWriteVersionedCacheableItem );
|
||||||
|
|
||||||
|
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem = new NonStrictReadWriteCacheableItem( BEFORE );
|
||||||
|
nonStrictReadWriteCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
nonStrictReadWriteCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( nonStrictReadWriteCacheableItem );
|
||||||
|
|
||||||
|
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem = new NonStrictReadWriteVersionedCacheableItem( BEFORE );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( nonStrictReadWriteVersionedCacheableItem );
|
||||||
|
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Session s1 = openSession();
|
||||||
|
s1.beginTransaction();
|
||||||
|
|
||||||
|
final String AFTER = "after";
|
||||||
|
|
||||||
|
ReadWriteCacheableItem readWriteCacheableItem1 = s1.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() );
|
||||||
|
readWriteCacheableItem1.setName( AFTER );
|
||||||
|
readWriteCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem1 = s1.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() );
|
||||||
|
readWriteVersionedCacheableItem1.setName( AFTER );
|
||||||
|
readWriteVersionedCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem1 = s1.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
|
||||||
|
nonStrictReadWriteCacheableItem1.setName( AFTER );
|
||||||
|
nonStrictReadWriteCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem1 = s1.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem1.setName( AFTER );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
s1.flush();
|
||||||
|
s1.refresh( readWriteCacheableItem1 );
|
||||||
|
s1.refresh( readWriteVersionedCacheableItem1 );
|
||||||
|
s1.refresh( nonStrictReadWriteCacheableItem1 );
|
||||||
|
s1.refresh( nonStrictReadWriteVersionedCacheableItem1 );
|
||||||
|
|
||||||
|
assertEquals( AFTER, readWriteCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, readWriteCacheableItem1.getTags().size() );
|
||||||
|
assertEquals( AFTER, readWriteVersionedCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, readWriteVersionedCacheableItem1.getTags().size() );
|
||||||
|
assertEquals( AFTER, nonStrictReadWriteCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteCacheableItem1.getTags().size() );
|
||||||
|
assertEquals( AFTER, nonStrictReadWriteVersionedCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem1.getTags().size() );
|
||||||
|
|
||||||
|
// open another session
|
||||||
|
Session s2 = sessionFactory().openSession();
|
||||||
|
try {
|
||||||
|
s2.beginTransaction();
|
||||||
|
ReadWriteCacheableItem readWriteCacheableItem2 = s2.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() );
|
||||||
|
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem2 = s2.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() );
|
||||||
|
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem2 = s2.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
|
||||||
|
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem2 = s2.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
|
||||||
|
|
||||||
|
assertEquals( BEFORE, readWriteCacheableItem2.getName() );
|
||||||
|
assertEquals( 2, readWriteCacheableItem2.getTags().size() );
|
||||||
|
assertEquals( BEFORE, readWriteVersionedCacheableItem2.getName() );
|
||||||
|
assertEquals( 2, readWriteVersionedCacheableItem2.getTags().size() );
|
||||||
|
|
||||||
|
//READ_UNCOMMITTED because there is no locking to prevent collections from being cached in the first Session
|
||||||
|
|
||||||
|
assertEquals( BEFORE, nonStrictReadWriteCacheableItem2.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteCacheableItem2.getTags().size());
|
||||||
|
assertEquals( BEFORE, nonStrictReadWriteVersionedCacheableItem2.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem2.getTags().size() );
|
||||||
|
|
||||||
|
s2.getTransaction().commit();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( s2.getTransaction().getStatus().canRollback() ) {
|
||||||
|
s2.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
s2.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
s1.getTransaction().rollback();
|
||||||
|
s1.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.delete( readWriteCacheableItem );
|
||||||
|
s.delete( readWriteVersionedCacheableItem );
|
||||||
|
s.delete( nonStrictReadWriteCacheableItem );
|
||||||
|
s.delete( nonStrictReadWriteVersionedCacheableItem );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "ReadWriteCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||||
|
public static class ReadWriteCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
public ReadWriteCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadWriteCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "ReadWriteVersionedCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||||
|
public static class ReadWriteVersionedCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private int version;
|
||||||
|
|
||||||
|
public ReadWriteVersionedCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadWriteVersionedCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "NonStrictReadWriteCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
|
||||||
|
public static class NonStrictReadWriteCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
public NonStrictReadWriteCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NonStrictReadWriteCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "NonStrictReadWriteVersionedCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
|
||||||
|
public static class NonStrictReadWriteVersionedCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private int version;
|
||||||
|
|
||||||
|
public NonStrictReadWriteVersionedCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NonStrictReadWriteVersionedCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
277
hibernate-ehcache/src/test/java/org/hibernate/test/cache/ehcache/functional/InsertedDataTest.java
vendored
Normal file
277
hibernate-ehcache/src/test/java/org/hibernate/test/cache/ehcache/functional/InsertedDataTest.java
vendored
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.ehcache.functional;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.Cache;
|
||||||
|
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for handling of data just inserted during a transaction being read from the database
|
||||||
|
* and placed into cache. Initially these cases went through putFromRead which causes problems because it
|
||||||
|
* loses the context of that data having just been read.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class InsertedDataTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {CacheableItem.class};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings( settings );
|
||||||
|
settings.put( AvailableSettings.CACHE_REGION_PREFIX, "" );
|
||||||
|
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.configure( "hibernate-config/hibernate.cfg.xml" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsert() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 1, cacheMap.size() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertWithRollback() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.flush();
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 0, cacheMap.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertThenUpdate() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.flush();
|
||||||
|
item.setName( "new data" );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 1, cacheMap.size() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertThenUpdateThenRollback() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.flush();
|
||||||
|
item.setName( "new data" );
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 0, cacheMap.size() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertWithRefresh() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.flush();
|
||||||
|
s.refresh( item );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 1, cacheMap.size() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertWithRefreshThenRollback() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.flush();
|
||||||
|
s.refresh( item );
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 1, cacheMap.size() );
|
||||||
|
Object lock = cacheMap.values().iterator().next();
|
||||||
|
assertEquals( "org.hibernate.cache.ehcache.internal.strategy.AbstractReadWriteEhcacheAccessStrategy$Lock", lock.getClass().getName() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
item = (CacheableItem) s.get( CacheableItem.class, item.getId() );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
assertNull( "it should be null", item );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertWithClear() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.flush();
|
||||||
|
s.clear();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 1, cacheMap.size() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.createQuery( "delete CacheableItem" ).executeUpdate();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertWithClearThenRollback() {
|
||||||
|
sessionFactory().getCache().evictEntityRegions();
|
||||||
|
sessionFactory().getStatistics().clear();
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
CacheableItem item = new CacheableItem( "data" );
|
||||||
|
s.save( item );
|
||||||
|
s.flush();
|
||||||
|
s.clear();
|
||||||
|
item = (CacheableItem) s.get( CacheableItem.class, item.getId() );
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Map cacheMap = sessionFactory().getStatistics().getSecondLevelCacheStatistics( "item" ).getEntries();
|
||||||
|
assertEquals( 0, cacheMap.size() );
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
item = (CacheableItem) s.get( CacheableItem.class, item.getId() );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
assertNull( "it should be null", item );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "CacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||||
|
public static class CacheableItem {
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public CacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(generator = "increment")
|
||||||
|
@GenericGenerator(name = "increment", strategy = "increment")
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,342 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.ehcache.functional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Version;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.Cache;
|
||||||
|
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zhenlei Huang
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-10649")
|
||||||
|
public class RefreshUpdatedDataTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
ReadWriteCacheableItem.class,
|
||||||
|
ReadWriteVersionedCacheableItem.class,
|
||||||
|
NonStrictReadWriteCacheableItem.class,
|
||||||
|
NonStrictReadWriteVersionedCacheableItem.class,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings( settings );
|
||||||
|
settings.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||||
|
super.configureStandardServiceRegistryBuilder( ssrb );
|
||||||
|
ssrb.configure( "hibernate-config/hibernate.cfg.xml" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAndFlushThenRefresh() {
|
||||||
|
// prepare data
|
||||||
|
Session s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
|
||||||
|
final String BEFORE = "before";
|
||||||
|
|
||||||
|
ReadWriteCacheableItem readWriteCacheableItem = new ReadWriteCacheableItem( BEFORE );
|
||||||
|
readWriteCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
readWriteCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( readWriteCacheableItem );
|
||||||
|
|
||||||
|
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem = new ReadWriteVersionedCacheableItem( BEFORE );
|
||||||
|
readWriteVersionedCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
readWriteVersionedCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( readWriteVersionedCacheableItem );
|
||||||
|
|
||||||
|
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem = new NonStrictReadWriteCacheableItem( BEFORE );
|
||||||
|
nonStrictReadWriteCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
nonStrictReadWriteCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( nonStrictReadWriteCacheableItem );
|
||||||
|
|
||||||
|
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem = new NonStrictReadWriteVersionedCacheableItem( BEFORE );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem.getTags().add( "Hibernate" );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem.getTags().add( "ORM" );
|
||||||
|
s.persist( nonStrictReadWriteVersionedCacheableItem );
|
||||||
|
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
Session s1 = openSession();
|
||||||
|
s1.beginTransaction();
|
||||||
|
|
||||||
|
final String AFTER = "after";
|
||||||
|
|
||||||
|
ReadWriteCacheableItem readWriteCacheableItem1 = s1.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() );
|
||||||
|
readWriteCacheableItem1.setName( AFTER );
|
||||||
|
readWriteCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem1 = s1.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() );
|
||||||
|
readWriteVersionedCacheableItem1.setName( AFTER );
|
||||||
|
readWriteVersionedCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem1 = s1.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
|
||||||
|
nonStrictReadWriteCacheableItem1.setName( AFTER );
|
||||||
|
nonStrictReadWriteCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem1 = s1.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem1.setName( AFTER );
|
||||||
|
nonStrictReadWriteVersionedCacheableItem1.getTags().remove("ORM");
|
||||||
|
|
||||||
|
s1.flush();
|
||||||
|
s1.refresh( readWriteCacheableItem1 );
|
||||||
|
s1.refresh( readWriteVersionedCacheableItem1 );
|
||||||
|
s1.refresh( nonStrictReadWriteCacheableItem1 );
|
||||||
|
s1.refresh( nonStrictReadWriteVersionedCacheableItem1 );
|
||||||
|
|
||||||
|
assertEquals( AFTER, readWriteCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, readWriteCacheableItem1.getTags().size() );
|
||||||
|
assertEquals( AFTER, readWriteVersionedCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, readWriteVersionedCacheableItem1.getTags().size() );
|
||||||
|
assertEquals( AFTER, nonStrictReadWriteCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteCacheableItem1.getTags().size() );
|
||||||
|
assertEquals( AFTER, nonStrictReadWriteVersionedCacheableItem1.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem1.getTags().size() );
|
||||||
|
|
||||||
|
// open another session
|
||||||
|
Session s2 = sessionFactory().openSession();
|
||||||
|
try {
|
||||||
|
s2.beginTransaction();
|
||||||
|
ReadWriteCacheableItem readWriteCacheableItem2 = s2.get( ReadWriteCacheableItem.class, readWriteCacheableItem.getId() );
|
||||||
|
ReadWriteVersionedCacheableItem readWriteVersionedCacheableItem2 = s2.get( ReadWriteVersionedCacheableItem.class, readWriteVersionedCacheableItem.getId() );
|
||||||
|
NonStrictReadWriteCacheableItem nonStrictReadWriteCacheableItem2 = s2.get( NonStrictReadWriteCacheableItem.class, nonStrictReadWriteCacheableItem.getId() );
|
||||||
|
NonStrictReadWriteVersionedCacheableItem nonStrictReadWriteVersionedCacheableItem2 = s2.get( NonStrictReadWriteVersionedCacheableItem.class, nonStrictReadWriteVersionedCacheableItem.getId() );
|
||||||
|
|
||||||
|
assertEquals( BEFORE, readWriteCacheableItem2.getName() );
|
||||||
|
assertEquals( 2, readWriteCacheableItem2.getTags().size() );
|
||||||
|
assertEquals( BEFORE, readWriteVersionedCacheableItem2.getName() );
|
||||||
|
assertEquals( 2, readWriteVersionedCacheableItem2.getTags().size() );
|
||||||
|
|
||||||
|
//READ_UNCOMMITTED because there is no locking to prevent collections from being cached in the first Session
|
||||||
|
|
||||||
|
assertEquals( BEFORE, nonStrictReadWriteCacheableItem2.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteCacheableItem2.getTags().size());
|
||||||
|
assertEquals( BEFORE, nonStrictReadWriteVersionedCacheableItem2.getName() );
|
||||||
|
assertEquals( 1, nonStrictReadWriteVersionedCacheableItem2.getTags().size() );
|
||||||
|
|
||||||
|
s2.getTransaction().commit();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ( s2.getTransaction().getStatus().canRollback() ) {
|
||||||
|
s2.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
s2.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
s1.getTransaction().rollback();
|
||||||
|
s1.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.beginTransaction();
|
||||||
|
s.delete( readWriteCacheableItem );
|
||||||
|
s.delete( readWriteVersionedCacheableItem );
|
||||||
|
s.delete( nonStrictReadWriteCacheableItem );
|
||||||
|
s.delete( nonStrictReadWriteVersionedCacheableItem );
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "ReadWriteCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||||
|
public static class ReadWriteCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
public ReadWriteCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadWriteCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "ReadWriteVersionedCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
|
||||||
|
public static class ReadWriteVersionedCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private int version;
|
||||||
|
|
||||||
|
public ReadWriteVersionedCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadWriteVersionedCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "NonStrictReadWriteCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
|
||||||
|
public static class NonStrictReadWriteCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
public NonStrictReadWriteCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NonStrictReadWriteCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "NonStrictReadWriteVersionedCacheableItem")
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "item")
|
||||||
|
public static class NonStrictReadWriteVersionedCacheableItem {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
|
||||||
|
@ElementCollection
|
||||||
|
private List<String> tags = new ArrayList<>();
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private int version;
|
||||||
|
|
||||||
|
public NonStrictReadWriteVersionedCacheableItem() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NonStrictReadWriteVersionedCacheableItem(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTags() {
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue