HHH-9764 : StaleObjectStateExceptions raising outside flush context

(cherry picked from commit c767b0ed15)
This commit is contained in:
Gail Badner 2015-12-14 13:37:58 -08:00
parent 56c1ae332d
commit 7af83f02ae
5 changed files with 210 additions and 40 deletions

View File

@ -12,6 +12,8 @@ import java.sql.SQLException;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreLogging;
@ -39,20 +41,22 @@ public abstract class AbstractLoadPlanBasedCollectionInitializer
private final QueryableCollection collectionPersister;
private final LoadQueryDetails staticLoadQuery;
private final LockOptions lockOptions;
public AbstractLoadPlanBasedCollectionInitializer(
QueryableCollection collectionPersister,
QueryBuildingParameters buildingParameters) {
super( collectionPersister.getFactory() );
this.collectionPersister = collectionPersister;
this.lockOptions = buildingParameters.getLockMode() != null
? new LockOptions( buildingParameters.getLockMode() )
: buildingParameters.getLockOptions();
final FetchStyleLoadPlanBuildingAssociationVisitationStrategy strategy =
new FetchStyleLoadPlanBuildingAssociationVisitationStrategy(
collectionPersister.getFactory(),
buildingParameters.getQueryInfluencers(),
buildingParameters.getLockMode() != null
? buildingParameters.getLockMode()
: buildingParameters.getLockOptions().getLockMode()
this.lockOptions.getLockMode()
);
final LoadPlan plan = MetamodelDrivenLoadPlanBuilder.buildRootCollectionLoadPlan( strategy, collectionPersister );
@ -79,6 +83,8 @@ public abstract class AbstractLoadPlanBasedCollectionInitializer
qp.setPositionalParameterValues( ids );
qp.setCollectionKeys( ids );
qp.setLockOptions( lockOptions );
executeLoad(
session,
qp,

View File

@ -124,7 +124,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
.getLockMode() != null ) {
return queryParameters.getLockOptions().getLockMode();
}
return LockMode.READ;
return LockMode.NONE;
}
private Map<EntityReference,EntityReferenceProcessingState> identifierResolutionContextMap;

View File

@ -283,40 +283,4 @@ public class CollectionCacheEvictionTest extends BaseCoreFunctionalTestCase {
}
s.close();
}
/**
* @author Guenther Demetz
*/
@TestForIssue(jiraKey = "HHH-9764")
@Test
public void testLockModes() {
Session s1 = openSession();
s1.beginTransaction();
Company company1 = (Company) s1.get( Company.class, 1 );
User user1 = (User) s1.get( User.class, 1 ); // into persistent context
/******************************************
*
*/
Session s2 = openSession();
s2.beginTransaction();
User user = (User) s2.get( User.class, 1 );
user.setName("TestUser");
s2.getTransaction().commit();
s2.close();
/******************************************
*
*/
// init cache of collection
assertEquals( 1, company1.getUsers().size() ); // raises org.hibernate.StaleObjectStateException if 2LCache is enabled
s1.getTransaction().commit();
s1.close();
}
}

View File

@ -19,11 +19,15 @@ import java.util.List;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
@Entity
public class Company {
@Id
int id;
String name;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@ -44,6 +48,14 @@ public class Company {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<User> getUsers() {
return users;
}

View File

@ -0,0 +1,188 @@
package org.hibernate.test.cache;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.hibernate.Hibernate;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.cache.internal.CollectionCacheInvalidator;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* @author Guenther Demetz
* @author Gail Badner
*/
public class LockModeTest extends BaseCoreFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { User.class, Company.class };
}
@Before
public void before() {
CollectionCacheInvalidator.PROPAGATE_EXCEPTION = true;
}
@After
public void after() {
CollectionCacheInvalidator.PROPAGATE_EXCEPTION = false;
}
@Override
protected void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( Environment.AUTO_EVICT_COLLECTION_CACHE, "true" );
cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
cfg.setProperty( Environment.USE_QUERY_CACHE, "true" );
cfg.setProperty( Environment.CACHE_PROVIDER_CONFIG, "true" );
}
@Override
protected void prepareTest() throws Exception {
Session s = openSession();
s.beginTransaction();
Company company1 = new Company( 1 );
s.save( company1 );
User user = new User( 1, company1 );
s.save( user );
Company company2 = new Company( 2 );
s.save( company2 );
s.getTransaction().commit();
s.close();
}
@Override
protected void cleanupTest() throws Exception {
Session s = openSession();
s.beginTransaction();
s.createQuery( "delete from org.hibernate.test.cache.User" ).executeUpdate();
s.createQuery( "delete from org.hibernate.test.cache.Company" ).executeUpdate();
s.getTransaction().commit();
s.close();
}
/**
*/
@TestForIssue(jiraKey = "HHH-9764")
@Test
public void testDefaultLockModeOnCollectionInitialization() {
Session s1 = openSession();
s1.beginTransaction();
Company company1 = s1.get( Company.class, 1 );
User user1 = s1.get( User.class, 1 ); // into persistent context
/******************************************
*
*/
Session s2 = openSession();
s2.beginTransaction();
User user = s2.get( User.class, 1 );
user.setName("TestUser");
s2.getTransaction().commit();
s2.close();
/******************************************
*
*/
// init cache of collection
assertEquals( 1, company1.getUsers().size() ); // raises org.hibernate.StaleObjectStateException if 2LCache is enabled
s1.getTransaction().commit();
s1.close();
}
@TestForIssue(jiraKey = "HHH-9764")
@Test
public void testDefaultLockModeOnEntityLoad() {
// first evict user
sessionFactory().getCache().evictEntity( User.class.getName(), 1 );
Session s1 = openSession();
s1.beginTransaction();
Company company1 = s1.get( Company.class, 1 );
/******************************************
*
*/
Session s2 = openSession();
s2.beginTransaction();
Company company = s2.get( Company.class, 1 );
company.setName( "TestCompany" );
s2.getTransaction().commit();
s2.close();
/******************************************
*
*/
User user1 = s1.get( User.class, 1 ); // into persistent context
// init cache of collection
assertNull( user1.getCompany().getName() ); // raises org.hibernate.StaleObjectStateException if 2LCache is enabled
s1.getTransaction().commit();
s1.close();
}
@TestForIssue(jiraKey = "HHH-9764")
@Test
public void testReadLockModeOnEntityLoad() {
// first evict user
sessionFactory().getCache().evictEntity( User.class.getName(), 1 );
Session s1 = openSession();
s1.beginTransaction();
Company company1 = s1.get( Company.class, 1 );
/******************************************
*
*/
Session s2 = openSession();
s2.beginTransaction();
Company company = s2.get( Company.class, 1 );
company.setName( "TestCompany" );
s2.getTransaction().commit();
s2.close();
/******************************************
*
*/
User user1 = s1.get( User.class, 1, LockMode.READ ); // into persistent context
// init cache of collection
assertNull( user1.getCompany().getName() ); // raises org.hibernate.StaleObjectStateException if 2LCache is enabled
s1.getTransaction().commit();
s1.close();
}
}