Tag Archives: collections

ehcache and hibernate: cache of collections

Last post I wrote about activating the hibernate second-level cache. Now, let’s see how to activate the second-level cache for collections.

In this example I’ll use a Customer with Orders. Please, take a look in the representation of the relationship between them, below:

Implementing the classes with Java will look like this:

package com.rodrigow;
class Order {
    int number;
}
package com.rodrigow;
import java.util.Set;
class Customer {
    String name;
    Set<Order> orders;
}

Now, the hibernate mapping:

<hibernate-mapping>
  <class name="com.rodrigow.Order" table="ORDER">
    <cache usage="read-only"/>
    <id name="number" type="int" />
  </class>
</hibernate-mapping>
<hibernate-mapping>
  <class name="com.rodrigow.Customer" table="CUSTOMER">
    <cache usage="read-only"/>
    <id name="name" type="java.lang.String" />
    <set name="orders" lazy="false">
      <cache usage="read-only" />
      <key column="number" />
      <one-to-many class="com.rodrigow.Order" />
    </set>
  </class>
</hibernate-mapping>

There is a configuration, in bold, that tells hibernate to look in the cache for objects of this type.

EHCache configuration (ehcache.xml) will became something like below:

<ehcache>
  <cache
    name="com.rodrigow.Customer"
    maxElementsInMemory="200"
    eternal="true"
    overflowToDisk="true"
  />
  <cache
    name="com.rodrigow.Customer.orders"
    maxElementsInMemory="200"
    eternal="true"
    overflowToDisk="true"
  />
</ehcache>

In bold we tell how it will find the objects. In order to find the client’s orders, it is needed to add an entry with the same name we gave in the class Client, i.e. orders.

Now everything is ready to go. No hits in the database!!! But wait… looking the hibernate logs I’m finding hits on the database for every single Order from a Client. But, should it be in the cache? What? Cache not found for the Order? AHHH!?!?!, Well, the documentation from EHCache it’s not that good, so, let’s dive into source code.

EHCache holds a cache version of the collection but it isn’t enough for hibernate to¬†hydrate¬†the objects. By the time it try to materialize the objects, hibernate look for each cache version of each Order and it does not find it, therefore hibernate ends up querying database for each Order from a Client.

Thus, we’ll need to add one more entry on ehcache.xml:

<ehcache>
  ...
  <cache
    name="com.rodrigow.Order"
    maxElementsInMemory="200"
    eternal="true"
    overflowToDisk="true"
  />
</ehcache>

Now you can check hibernate logs and actually see the cache hits for each order on the customer!