Skip to content

Commit

Permalink
HHH-9764 : StaleObjectStateExceptions raising outside flush context
Browse files Browse the repository at this point in the history
  • Loading branch information
gbadner committed Dec 14, 2015
1 parent 840d906 commit c767b0e
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 40 deletions.
Expand Up @@ -12,6 +12,8 @@


import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
Expand Down Expand Up @@ -39,20 +41,22 @@ public abstract class AbstractLoadPlanBasedCollectionInitializer


private final QueryableCollection collectionPersister; private final QueryableCollection collectionPersister;
private final LoadQueryDetails staticLoadQuery; private final LoadQueryDetails staticLoadQuery;
private final LockOptions lockOptions;


public AbstractLoadPlanBasedCollectionInitializer( public AbstractLoadPlanBasedCollectionInitializer(
QueryableCollection collectionPersister, QueryableCollection collectionPersister,
QueryBuildingParameters buildingParameters) { QueryBuildingParameters buildingParameters) {
super( collectionPersister.getFactory() ); super( collectionPersister.getFactory() );
this.collectionPersister = collectionPersister; this.collectionPersister = collectionPersister;
this.lockOptions = buildingParameters.getLockMode() != null
? new LockOptions( buildingParameters.getLockMode() )
: buildingParameters.getLockOptions();


final FetchStyleLoadPlanBuildingAssociationVisitationStrategy strategy = final FetchStyleLoadPlanBuildingAssociationVisitationStrategy strategy =
new FetchStyleLoadPlanBuildingAssociationVisitationStrategy( new FetchStyleLoadPlanBuildingAssociationVisitationStrategy(
collectionPersister.getFactory(), collectionPersister.getFactory(),
buildingParameters.getQueryInfluencers(), buildingParameters.getQueryInfluencers(),
buildingParameters.getLockMode() != null this.lockOptions.getLockMode()
? buildingParameters.getLockMode()
: buildingParameters.getLockOptions().getLockMode()
); );


final LoadPlan plan = MetamodelDrivenLoadPlanBuilder.buildRootCollectionLoadPlan( strategy, collectionPersister ); final LoadPlan plan = MetamodelDrivenLoadPlanBuilder.buildRootCollectionLoadPlan( strategy, collectionPersister );
Expand All @@ -79,6 +83,8 @@ public void initialize(Serializable id, SessionImplementor session)
qp.setPositionalParameterValues( ids ); qp.setPositionalParameterValues( ids );
qp.setCollectionKeys( ids ); qp.setCollectionKeys( ids );


qp.setLockOptions( lockOptions );

executeLoad( executeLoad(
session, session,
qp, qp,
Expand Down
Expand Up @@ -124,7 +124,7 @@ public LockMode resolveLockMode(EntityReference entityReference) {
.getLockMode() != null ) { .getLockMode() != null ) {
return queryParameters.getLockOptions().getLockMode(); return queryParameters.getLockOptions().getLockMode();
} }
return LockMode.READ; return LockMode.NONE;
} }


private Map<EntityReference,EntityReferenceProcessingState> identifierResolutionContextMap; private Map<EntityReference,EntityReferenceProcessingState> identifierResolutionContextMap;
Expand Down
Expand Up @@ -283,40 +283,4 @@ public void testCollectionCacheEvictionUpdateWithEntityOutOfContext() {
} }
s.close(); 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();
}
} }
12 changes: 12 additions & 0 deletions hibernate-core/src/test/java/org/hibernate/test/cache/Company.java
Expand Up @@ -19,11 +19,15 @@


import org.hibernate.annotations.Cache; import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;


@Entity @Entity
public class Company { public class Company {
@Id @Id
int id; int id;

String name;


@OneToMany(fetch = FetchType.LAZY, mappedBy = "company") @OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
Expand All @@ -44,6 +48,14 @@ public void setId(int id) {
this.id = id; this.id = id;
} }


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<User> getUsers() { public List<User> getUsers() {
return users; return users;
} }
Expand Down
@@ -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();
}

}

1 comment on commit c767b0e

@pb00068
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting., so finally return LockMode.READ at ResultSetProcessingContextImpl.java line 127 was just some kind of typo?

Please sign in to comment.