You were absolutely right. I had added the <cache usage="read-only" /> to the mapping of the object I wanted to cache and then later removed it. I forgot to put it back after adding the statistics testing. The 2nd-level cache does indeed seem to be working.
Unfortunately it's not solving my problem like I thought it would. I'm trying to cache a users profile data so that I don't get LazyInitializationExceptions when they go to different pages. The users profile data contains a list of lazily loaded objects so I want to put the users profile in the 2nd-level cache so it's not tied to a specific Session but to the SessionFactory. But I'm still getting LazyInitializationExceptions.
Here's the mapping file for the UserBackingData object that is persisted by Hibernate:
Code:
<hibernate-mapping>
<class name="com.contentconnections.mpl.publisher.auth.UserBackingData" table="mpl_users">
<id name="uid" column="uid" >
<generator class="uuid" />
</id>
<natural-id mutable="true">
<property name="username" />
</natural-id>
<property name="password" />
<set name="authorities" table="mpl_authorities" lazy="true">
<key column="uid" />
<composite-element class="com.contentconnections.mpl.publisher.auth.MutableGrantedAuthority">
<property name="authority" />
</composite-element>
</set>
<one-to-one name="profile" lazy="false" />
</class>
</hibernate-mapping>
And the mapping of the Profile class is here:
Code:
<?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-mapping>
<class name="com.contentconnections.mpl.publisher.Profile" table="mpl_profiles" discriminator-value="P" lazy="false">
<id name="uid" column="uid" type="string">
<generator class="assigned" />
</id>
<discriminator column="type" type="character" />
<property name="firstName" />
<property name="lastName" />
<property name="email" />
<subclass name="com.contentconnections.mpl.publisher.CourseAdministratorProfile" discriminator-value="C">
<set name="prefixes" table="mpl_courseadmin_prefixes" inverse="true">
<key column="courseadmin_uid" />
<many-to-many column="prefix" class="com.contentconnections.mpl.publisher.RegistrationCodePrefix" />
</set>
</subclass>
<subclass name="com.contentconnections.mpl.publisher.RegisteredUserProfile" discriminator-value="R">
<property name="contactAllowed" not-null="true" />
<many-to-one name="registrationCode" column="registrationCode" />
<subclass name="com.contentconnections.mpl.publisher.StudentProfile" discriminator-value="S">
<property name="major" />
<property name="year" />
</subclass>
<subclass name="com.contentconnections.mpl.publisher.InstructorProfile" discriminator-value="I">
<property name="institution" />
<property name="department" />
<property name="city" />
<property name="state" />
<property name="postalCode" />
<property name="workPhone" />
</subclass>
</subclass>
</class>
</hibernate-mapping>
I'm using Spring to configure and create a SessionFactory, so here's that configuration:
Code:
<!-- Hibernate SessionFactory Definition -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2dll.auto}</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">${hibernate.cglib.use_reflection_optimizer}</prop>
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
<!--<prop key="hibernate.transaction.manager_lookup_class">org.springframework.orm.hibernate3.LocalTransactionManagerLookup</prop>-->
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
<prop key="hibernate.cache.use_structured_entries">${hibernate.cache.use_structured_entries}</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/contentconnections/mpl/publisher/Course.hbm.xml</value>
<value>com/contentconnections/mpl/publisher/CourseAdministrationTask.hbm.xml</value>
<value>com/contentconnections/mpl/publisher/Profile.hbm.xml</value>
<value>com/contentconnections/mpl/publisher/Question.hbm.xml</value>
<value>com/contentconnections/mpl/publisher/RegistrationCode.hbm.xml</value>
<value>com/contentconnections/mpl/publisher/RegistrationCodePrefix.hbm.xml</value>
<value>com/contentconnections/mpl/publisher/User.hbm.xml</value>
</list>
</property>
<property name="entityCacheStrategies">
<props>
<prop key="com.contentconnections.mpl.publisher.auth.UserBackingData">read-write</prop>
<prop key="com.contentconnections.mpl.publisher.Profile">read-write</prop>
</props>
</property>
<property name="collectionCacheStrategies">
<props>
<prop key="com.contentconnections.mpl.publisher.CourseAdministratorProfile.prefixes">read-only</prop>
</props>
</property>
<property name="dataSource"><ref bean="dataSource" /></property>
</bean>
When I need to authenticate a user I do a find() on their username to get their uid and then a load() on the uid to make sure the UserBackingData is put into the 2nd-level cache. I've tried to make sure the users profile is put in the cache as well by specifying it in the entityCacheStrategies list which is equivalent to putting
Code:
<class-cache class="com.contentconnections.mpl.publisher.Profile" usage="read-write"/>
in the hibernate.cfg.xml file. And I've tried to make sure that the prefixes collection of the CourseAdministratorProfile subclass of Profile is cached by putting it in the collectionCacheStrategies properties.
But, when trying to access the prefixes collection in a different hibernate session from the one that loaded the UserBackingData I'm still getting a LazyInitializationException.
Any ideas? Is this a valid usage of the 2nd-level cache?
Thanks,
Rich