diff --git a/hibernate-core/src/main/java/org/hibernate/loader/collection/plan/AbstractLoadPlanBasedCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/loader/collection/plan/AbstractLoadPlanBasedCollectionInitializer.java index 5b044a8e44..6409685a9c 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/collection/plan/AbstractLoadPlanBasedCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/collection/plan/AbstractLoadPlanBasedCollectionInitializer.java @@ -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, diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java index 7fbbe25d53..1ec0acd7b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/ResultSetProcessingContextImpl.java @@ -124,7 +124,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex .getLockMode() != null ) { return queryParameters.getLockOptions().getLockMode(); } - return LockMode.READ; + return LockMode.NONE; } private Map identifierResolutionContextMap; diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java index af496670ad..9c559cf98c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/CollectionCacheEvictionTest.java @@ -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(); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/Company.java b/hibernate-core/src/test/java/org/hibernate/test/cache/Company.java index 71a8c4c367..fadf5f9a4a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/Company.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/Company.java @@ -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 getUsers() { return users; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/LockModeTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/LockModeTest.java new file mode 100644 index 0000000000..0bfa7a4442 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/LockModeTest.java @@ -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(); + } + +}