From 691b5b616b3de61f71968d29a2db71cb563bb74c Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 17 Aug 2010 03:28:30 +0000 Subject: [PATCH] HHH-5180 : StandardQueryCache.get() does not handle EntityNotFoundException for natural key lookups git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@20153 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../hibernate/cache/StandardQueryCache.java | 10 +- .../hibernate/test/jpa/AbstractJPATest.java | 30 +- .../jpa/naturalid/ImmutableNaturalIdTest.java | 264 ++++++++++++++++++ .../hibernate/test/jpa/naturalid/User.hbm.xml | 42 +++ .../hibernate/test/jpa/naturalid/User.java | 89 ++++++ .../test/jpa/proxy/JPAProxyTest.java | 2 + .../immutable/ImmutableNaturalIdTest.java | 95 +++++++ .../mutable/MutableNaturalIdTest.java | 109 ++++++++ 8 files changed, 610 insertions(+), 31 deletions(-) create mode 100644 testsuite/src/test/java/org/hibernate/test/jpa/naturalid/ImmutableNaturalIdTest.java create mode 100644 testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.hbm.xml create mode 100644 testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.java diff --git a/core/src/main/java/org/hibernate/cache/StandardQueryCache.java b/core/src/main/java/org/hibernate/cache/StandardQueryCache.java index 85425211ac..6f8c19c5bf 100644 --- a/core/src/main/java/org/hibernate/cache/StandardQueryCache.java +++ b/core/src/main/java/org/hibernate/cache/StandardQueryCache.java @@ -29,6 +29,8 @@ import java.util.List; import java.util.Properties; import java.util.Set; +import javax.persistence.EntityNotFoundException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -156,8 +158,10 @@ public class StandardQueryCache implements QueryCache { ); } } - catch ( UnresolvableObjectException uoe ) { - if ( isNaturalKeyLookup ) { + catch ( RuntimeException ex ) { + if ( isNaturalKeyLookup && + ( UnresolvableObjectException.class.isInstance( ex ) || + EntityNotFoundException.class.isInstance( ex ) ) ) { //TODO: not really completely correct, since // the uoe could occur while resolving // associations, leaving the PC in an @@ -167,7 +171,7 @@ public class StandardQueryCache implements QueryCache { return null; } else { - throw uoe; + throw ex; } } } diff --git a/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java b/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java index c37154bc81..6f2ca5b9b1 100644 --- a/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java +++ b/testsuite/src/test/java/org/hibernate/test/jpa/AbstractJPATest.java @@ -16,6 +16,7 @@ import org.hibernate.util.IdentityMap; import org.hibernate.testing.junit.functional.FunctionalTestCase; import java.io.Serializable; +import javax.persistence.EntityNotFoundException; /** * An abstract test for all JPA spec related tests. @@ -53,37 +54,10 @@ public abstract class AbstractJPATest extends FunctionalTestCase { private static class JPAEntityNotFoundDelegate implements EntityNotFoundDelegate { public void handleEntityNotFound(String entityName, Serializable id) { - throw new EntityNotFoundException( entityName, id ); + throw new EntityNotFoundException("Unable to find " + entityName + " with id " + id); } } - /** - * Mimic the JPA EntityNotFoundException. - */ - public static class EntityNotFoundException extends RuntimeException { - private final String entityName; - private final Serializable id; - - public EntityNotFoundException(String entityName, Serializable id) { - this( "unable to locate specified entity", entityName, id ); - } - - public EntityNotFoundException(String message, String entityName, Serializable id) { - super( message ); - this.entityName = entityName; - this.id = id; - } - - public String getEntityName() { - return entityName; - } - - public Serializable getId() { - return id; - } - } - - // mimic specific event aspects of the JPA environment ~~~~~~~~~~~~~~~~~~~~ protected PersistEventListener[] buildPersistEventListeners() { diff --git a/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/ImmutableNaturalIdTest.java b/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/ImmutableNaturalIdTest.java new file mode 100644 index 0000000000..196a1ceea7 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/ImmutableNaturalIdTest.java @@ -0,0 +1,264 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + * + */ +package org.hibernate.test.jpa.naturalid; + +import junit.framework.Test; + +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.criterion.Restrictions; +import org.hibernate.test.jpa.AbstractJPATest; +import org.hibernate.testing.junit.functional.FunctionalTestClassTestSuite; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + * (copied from org.hibernate.test.naturalid.immutable.ImmutableNaturalIdTest) + */ +public class ImmutableNaturalIdTest extends AbstractJPATest { + public ImmutableNaturalIdTest(String string) { + super( string ); + } + + public String[] getMappings() { + return new String[] { "jpa/naturalid/User.hbm.xml" }; + } + + public static Test suite() { + return new FunctionalTestClassTestSuite( ImmutableNaturalIdTest.class ); + } + + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" ); + cfg.setProperty( Environment.USE_QUERY_CACHE, "true" ); + cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); + } + + public void testUpdate() { + // prepare some test data... + Session session = openSession(); + session.beginTransaction(); + User user = new User(); + user.setUserName( "steve" ); + user.setEmail( "steve@hibernate.org" ); + user.setPassword( "brewhaha" ); + session.save( user ); + session.getTransaction().commit(); + session.close(); + + // 'user' is now a detached entity, so lets change a property and reattch... + user.setPassword( "homebrew" ); + session = openSession(); + session.beginTransaction(); + session.update( user ); + session.getTransaction().commit(); + session.close(); + + // clean up + session = openSession(); + session.beginTransaction(); + session.delete( user ); + session.getTransaction().commit(); + session.close(); + } + + public void testNaturalIdCheck() throws Exception { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + User u = new User( "steve", "superSecret" ); + s.persist( u ); + u.setUserName( "Steve" ); + try { + s.flush(); + fail(); + } + catch ( HibernateException he ) { + } + u.setUserName( "steve" ); + s.delete( u ); + t.commit(); + s.close(); + } + + public void testNaturalIdCache() { + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "superSecret" ); + s.persist( u ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + s.getTransaction().commit(); + s.close(); + + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 ); + + s = openSession(); + s.beginTransaction(); + User v = new User( "gavin", "supsup" ); + s.persist( v ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 ); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 2 ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete User" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } + + public void testNaturalIdDeleteUsingCache() { + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "superSecret" ); + s.persist( u ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + s.getTransaction().commit(); + s.close(); + + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 ); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 ); + + s.delete( u ); + + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNull( u ); + s.getTransaction().commit(); + s.close(); + } + + public void testNaturalIdRecreateUsingCache() { + testNaturalIdDeleteUsingCache(); + + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "superSecret" ); + s.persist( u ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 ); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 ); + + s.delete( u ); + + s.getTransaction().commit(); + s.close(); + } + +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.hbm.xml b/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.hbm.xml new file mode 100644 index 0000000000..0ddd6849e7 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.hbm.xml @@ -0,0 +1,42 @@ + + + + + + + + + + Users may bid for or sell auction items. + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.java b/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.java new file mode 100644 index 0000000000..bcf9ac7e83 --- /dev/null +++ b/testsuite/src/test/java/org/hibernate/test/jpa/naturalid/User.java @@ -0,0 +1,89 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, Red Hat Middleware LLC or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Middleware LLC. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + * + */ +package org.hibernate.test.jpa.naturalid; + +/** + * {@inheritDoc} + * + * @author Steve Ebersole + * (copied from org.hibernate.test.naturalid.immutable.User) + */ +public class User implements java.io.Serializable { + + private Integer myUserId; + private Integer version; + private String userName; + private String password; + private String email; + + public User() { + } + + public User(String userName, String password) { + this.userName = userName; + this.password = password; + } + + public Integer getMyUserId() { + return this.myUserId; + } + + public void setMyUserId(Integer myUserId) { + this.myUserId = myUserId; + } + + public String getUserName() { + return this.userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return this.email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Integer getVersion() { + return this.version; + } + + public void setVersion(Integer version) { + this.version = version; + } + +} \ No newline at end of file diff --git a/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java b/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java index e01d525806..8c0a694134 100644 --- a/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java +++ b/testsuite/src/test/java/org/hibernate/test/jpa/proxy/JPAProxyTest.java @@ -1,5 +1,7 @@ package org.hibernate.test.jpa.proxy; +import javax.persistence.EntityNotFoundException; + import junit.framework.AssertionFailedError; import junit.framework.Test; diff --git a/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableNaturalIdTest.java b/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableNaturalIdTest.java index 0bce11d40c..6e20e4fe8f 100644 --- a/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableNaturalIdTest.java +++ b/testsuite/src/test/java/org/hibernate/test/naturalid/immutable/ImmutableNaturalIdTest.java @@ -155,4 +155,99 @@ public class ImmutableNaturalIdTest extends FunctionalTestCase { s.getTransaction().commit(); s.close(); } + + public void testNaturalIdDeleteUsingCache() { + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "superSecret" ); + s.persist( u ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + s.getTransaction().commit(); + s.close(); + + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 ); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 ); + + s.delete( u ); + + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNull( u ); + s.getTransaction().commit(); + s.close(); + } + + public void testNaturalIdRecreateUsingCache() { + testNaturalIdDeleteUsingCache(); + + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "superSecret" ); + s.persist( u ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 ); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId().set( "userName", "steve" ) ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 ); + + s.delete( u ); + + s.getTransaction().commit(); + s.close(); + } + } diff --git a/testsuite/src/test/java/org/hibernate/test/naturalid/mutable/MutableNaturalIdTest.java b/testsuite/src/test/java/org/hibernate/test/naturalid/mutable/MutableNaturalIdTest.java index 7515cd2548..c5feab2893 100755 --- a/testsuite/src/test/java/org/hibernate/test/naturalid/mutable/MutableNaturalIdTest.java +++ b/testsuite/src/test/java/org/hibernate/test/naturalid/mutable/MutableNaturalIdTest.java @@ -244,6 +244,115 @@ public class MutableNaturalIdTest extends FunctionalTestCase { s.close(); } + public void testNaturalIdDeleteUsingCache() { + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "hb", "superSecret" ); + s.persist( u ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId() + .set("name", "steve") + .set("org", "hb") + ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + s.getTransaction().commit(); + s.close(); + + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 ); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId() + .set("name", "steve") + .set("org", "hb") + ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 ); + + s.delete( u ); + + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId() + .set("name", "steve") + .set("org", "hb") + ) + .setCacheable( true ) + .uniqueResult(); + assertNull( u ); + s.getTransaction().commit(); + s.close(); + } + + public void testNaturalIdRecreateUsingCache() { + testNaturalIdDeleteUsingCache(); + + Session s = openSession(); + s.beginTransaction(); + User u = new User( "steve", "hb", "superSecret" ); + s.persist( u ); + s.getTransaction().commit(); + s.close(); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId() + .set("name", "steve") + .set("org", "hb") + ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 ); + + getSessions().getStatistics().clear(); + + s = openSession(); + s.beginTransaction(); + u = ( User ) s.createCriteria( User.class ) + .add( Restrictions.naturalId() + .set("name", "steve") + .set("org", "hb") + ) + .setCacheable( true ) + .uniqueResult(); + assertNotNull( u ); + assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 ); + assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 ); + + s.delete( u ); + + s.getTransaction().commit(); + s.close(); + } + public void testQuerying() throws Exception { Session s = openSession(); Transaction t = s.beginTransaction();