HHH-9764 : StaleObjectStateExceptions raising outside flush context
(cherry picked from commit c767b0ed15
)
This commit is contained in:
parent
56c1ae332d
commit
7af83f02ae
|
@ -12,6 +12,8 @@ import java.sql.SQLException;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -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 );
|
||||||
|
@ -79,6 +83,8 @@ public abstract class AbstractLoadPlanBasedCollectionInitializer
|
||||||
qp.setPositionalParameterValues( ids );
|
qp.setPositionalParameterValues( ids );
|
||||||
qp.setCollectionKeys( ids );
|
qp.setCollectionKeys( ids );
|
||||||
|
|
||||||
|
qp.setLockOptions( lockOptions );
|
||||||
|
|
||||||
executeLoad(
|
executeLoad(
|
||||||
session,
|
session,
|
||||||
qp,
|
qp,
|
||||||
|
|
|
@ -124,7 +124,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
|
||||||
.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;
|
||||||
|
|
|
@ -283,40 +283,4 @@ public class CollectionCacheEvictionTest extends BaseCoreFunctionalTestCase {
|
||||||
}
|
}
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,16 @@ import java.util.List;
|
||||||
|
|
||||||
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)
|
||||||
List<User> users = new ArrayList<User>();
|
List<User> users = new ArrayList<User>();
|
||||||
|
@ -44,6 +48,14 @@ public class Company {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue