HHH-2892 : natural id caching

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14083 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2007-10-16 21:04:09 +00:00
parent 8d12b2e61f
commit 12cf197f2f
7 changed files with 268 additions and 130 deletions

View File

@ -2147,23 +2147,18 @@ public abstract class Loader {
}
private List getResultFromQueryCache(
final SessionImplementor session,
final QueryParameters queryParameters,
final Set querySpaces,
final SessionImplementor session,
final QueryParameters queryParameters,
final Set querySpaces,
final Type[] resultTypes,
final QueryCache queryCache,
final QueryCache queryCache,
final QueryKey key) {
List result = null;
if ( session.getCacheMode().isGetEnabled() ) {
result = queryCache.get(
key,
resultTypes,
queryParameters.isNaturalKeyLookup(),
querySpaces,
session
);
if ( session.getCacheMode().isGetEnabled() ) {
boolean isImmutableNaturalKeyLookup = queryParameters.isNaturalKeyLookup()
&& getEntityPersisters()[0].getEntityMetamodel().hasImmutableNaturalId();
result = queryCache.get( key, resultTypes, isImmutableNaturalKeyLookup, querySpaces, session );
if ( factory.getStatistics().isStatisticsEnabled() ) {
if ( result == null ) {
factory.getStatisticsImplementor()
@ -2174,28 +2169,20 @@ public abstract class Loader {
.queryCacheHit( getQueryIdentifier(), queryCache.getRegion().getName() );
}
}
}
return result;
}
private void putResultInQueryCache(
final SessionImplementor session,
final QueryParameters queryParameters,
final SessionImplementor session,
final QueryParameters queryParameters,
final Type[] resultTypes,
final QueryCache queryCache,
final QueryKey key,
final QueryCache queryCache,
final QueryKey key,
final List result) {
if ( session.getCacheMode().isPutEnabled() ) {
boolean put = queryCache.put(
key,
resultTypes,
result,
queryParameters.isNaturalKeyLookup(),
session
);
boolean put = queryCache.put( key, resultTypes, result, queryParameters.isNaturalKeyLookup(), session );
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor()
.queryCachePut( getQueryIdentifier(), queryCache.getRegion().getName() );

View File

@ -82,6 +82,7 @@ public class EntityMetamodel implements Serializable {
private final boolean hasNonIdentifierPropertyNamedId;
private final int[] naturalIdPropertyNumbers;
private final boolean hasImmutableNaturalId;
private boolean lazy; //not final because proxy factory creation can fail
private final boolean hasCascades;
@ -159,6 +160,7 @@ public class EntityMetamodel implements Serializable {
boolean foundNonIdentifierPropertyNamedId = false;
boolean foundInsertGeneratedValue = false;
boolean foundUpdateGeneratedValue = false;
boolean foundUpdateableNaturalIdProperty = false;
while ( iter.hasNext() ) {
Property prop = ( Property ) iter.next();
@ -173,6 +175,9 @@ public class EntityMetamodel implements Serializable {
if ( prop.isNaturalIdentifier() ) {
naturalIdNumbers.add( new Integer(i) );
if ( prop.isUpdateable() ) {
foundUpdateableNaturalIdProperty = true;
}
}
if ( "id".equals( prop.getName() ) ) {
@ -229,9 +234,11 @@ public class EntityMetamodel implements Serializable {
if (naturalIdNumbers.size()==0) {
naturalIdPropertyNumbers = null;
hasImmutableNaturalId = false;
}
else {
naturalIdPropertyNumbers = ArrayHelper.toIntArray(naturalIdNumbers);
hasImmutableNaturalId = !foundUpdateableNaturalIdProperty;
}
hasInsertGeneratedValues = foundInsertGeneratedValue;
@ -373,6 +380,10 @@ public class EntityMetamodel implements Serializable {
return naturalIdPropertyNumbers!=null;
}
public boolean hasImmutableNaturalId() {
return hasImmutableNaturalId;
}
public Set getSubclassEntityNames() {
return subclassEntityNames;
}

View File

@ -1,8 +1,28 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.test.naturalid.immutable;
import junit.framework.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.criterion.Restrictions;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
@ -24,6 +44,12 @@ public class ImmutableNaturalIdTest extends FunctionalTestCase {
return new FunctionalTestClassTestSuite( ImmutableNaturalIdTest.class );
}
public void configure(Configuration 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();
@ -31,9 +57,6 @@ public class ImmutableNaturalIdTest extends FunctionalTestCase {
User user = new User();
user.setUserName( "steve" );
user.setEmail( "steve@hibernate.org" );
user.setFirstName( "Steve" );
user.setInitial( null);
user.setLastName( "Ebersole" );
user.setPassword( "brewhaha" );
session.save( user );
session.getTransaction().commit();
@ -54,4 +77,82 @@ public class ImmutableNaturalIdTest extends FunctionalTestCase {
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();
}
}

View File

@ -1,11 +1,32 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
~ Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
~
~ 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, v. 2.1. This program is distributed in the
~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
~ distribution; if not, write to the Free Software Foundation, Inc.,
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
~
~ Red Hat Author(s): Steve Ebersole
-->
<!--
This mapping illustrates use of <natural-id mutable="false"/>
-->
<hibernate-mapping package="org.hibernate.test.naturalid.immutable">
<class name="User" table="IMM_NAT_ID_USER" lazy="true">
<class name="User" table="IMM_NAT_ID_USER" lazy="true">
<comment>Users may bid for or sell auction items.</comment>
<id name="myUserId" type="java.lang.Integer">
<generator class="increment"/>
@ -16,9 +37,6 @@
<version name="version"/>
<property name="password" not-null="true" length="15" column="`password`"/>
<property name="email"/>
<property name="firstName" length="50" not-null="true"/>
<property name="initial" column="`initial`"/>
<property name="lastName" length="50" not-null="true"/>
</class>
</hibernate-mapping>

View File

@ -1,3 +1,18 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.test.naturalid.immutable;
/**
@ -12,13 +27,15 @@ public class User implements java.io.Serializable {
private String userName;
private String password;
private String email;
private String firstName;
private Character initial;
private String lastName;
public User() {
}
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
public Integer getMyUserId() {
return this.myUserId;
}
@ -51,30 +68,6 @@ public class User implements java.io.Serializable {
this.email = email;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public Character getInitial() {
return this.initial;
}
public void setInitial(Character initial) {
this.initial = initial;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getVersion() {
return this.version;
}

View File

@ -1,4 +1,4 @@
//$Id: MutableNaturalIdTest.java 10977 2006-12-12 23:28:04Z steve.ebersole@jboss.com $
//$Id: MutableNaturalIdTest.java 11645 2007-06-06 21:33:31Z steve.ebersole@jboss.com $
package org.hibernate.test.naturalid.mutable;
import java.lang.reflect.Field;
@ -8,7 +8,6 @@ import junit.framework.Test;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.test.naturalid.mutable.User;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.criterion.Restrictions;
@ -19,7 +18,7 @@ import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
* @author Gavin King
*/
public class MutableNaturalIdTest extends FunctionalTestCase {
public MutableNaturalIdTest(String str) {
super(str);
}
@ -37,98 +36,117 @@ public class MutableNaturalIdTest extends FunctionalTestCase {
public static Test suite() {
return new FunctionalTestClassTestSuite( MutableNaturalIdTest.class );
}
public void testNaturalIdCheck() throws Exception {
public void testReattachmentNaturalIdCheck() throws Throwable {
Session s = openSession();
Transaction t = s.beginTransaction();
User u = new User("gavin", "hb", "secret");
s.persist(u);
s.beginTransaction();
User u = new User( "gavin", "hb", "secret" );
s.persist( u );
s.getTransaction().commit();
s.close();
Field name = u.getClass().getDeclaredField("name");
name.setAccessible(true);
name.set(u, "Gavin");
s = openSession();
s.beginTransaction();
try {
s.flush();
fail();
s.update( u );
s.getTransaction().commit();
}
catch (HibernateException he) {}
name.set(u, "gavin");
s.delete(u);
t.commit();
catch( HibernateException expected ) {
s.getTransaction().rollback();
}
catch( Throwable t ) {
try {
s.getTransaction().rollback();
}
catch ( Throwable ignore ) {
}
throw t;
}
finally {
s.close();
}
s = openSession();
s.beginTransaction();
s.delete( u );
s.getTransaction().commit();
s.close();
}
public void testNonexistentNaturalIdCache() {
getSessions().getStatistics().clear();
Session s = openSession();
Transaction t = s.beginTransaction();
Object nullUser = s.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
.set("org", "hb")
)
.setCacheable(true)
.uniqueResult();
assertNull(nullUser);
t.commit();
s.close();
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 0 );
s = openSession();
t = s.beginTransaction();
User u = new User("gavin", "hb", "secret");
s.persist(u);
t.commit();
s.close();
getSessions().getStatistics().clear();
s = openSession();
t = s.beginTransaction();
u = (User) s.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
.set("org", "hb")
)
.setCacheable(true)
.uniqueResult();
assertNotNull(u);
t.commit();
s.close();
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 );
getSessions().getStatistics().clear();
s = openSession();
t = s.beginTransaction();
u = (User) s.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
.set("org", "hb")
).setCacheable(true)
.uniqueResult();
s.delete(u);
t.commit();
s.close();
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 );
@ -136,86 +154,96 @@ public class MutableNaturalIdTest extends FunctionalTestCase {
s = openSession();
t = s.beginTransaction();
nullUser = s.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
.set("org", "hb")
)
.setCacheable(true)
.uniqueResult();
assertNull(nullUser);
t.commit();
s.close();
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 0 );
}
public void testNaturalIdCache() {
Session s = openSession();
Transaction t = s.beginTransaction();
User u = new User("gavin", "hb", "secret");
s.persist(u);
t.commit();
s.close();
getSessions().getStatistics().clear();
s = openSession();
t = s.beginTransaction();
u = (User) s.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
.set("org", "hb")
)
.setCacheable(true)
.uniqueResult();
assertNotNull(u);
t.commit();
s.close();
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
assertEquals( getSessions().getStatistics().getQueryCachePutCount(), 1 );
s = openSession();
t = s.beginTransaction();
User v = new User("xam", "hb", "foobar");
s.persist(v);
t.commit();
s.close();
getSessions().getStatistics().clear();
s = openSession();
t = s.beginTransaction();
u = (User) s.createCriteria(User.class)
u = (User) s.createCriteria( User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
.set("org", "hb")
).setCacheable(true)
.uniqueResult();
assertNotNull(u);
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 0 );
u = (User) s.createCriteria( User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
).setCacheable(true)
.uniqueResult();
assertNotNull(u);
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 1 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 );
t.commit();
s.close();
assertEquals( getSessions().getStatistics().getQueryExecutionCount(), 0 );
assertEquals( getSessions().getStatistics().getQueryCacheHitCount(), 1 );
s = openSession();
t = s.beginTransaction();

View File

@ -1,27 +1,27 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
This mapping illustrates use of <natural-id>.
This mapping illustrates use of <natural-id mutable="true"/>
-->
<hibernate-mapping
<hibernate-mapping
package="org.hibernate.test.naturalid"
default-access="field">
<class name="org.hibernate.test.naturalid.mutable.User" table="SystemUserInfo">
<id name="id">
<generator class="increment"/>
</id>
<natural-id>
<natural-id mutable="true">
<property name="name"/>
<property name="org"/>
</natural-id>
<property name="password"/>
</class>
</hibernate-mapping>