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!

4 thoughts on “ehcache and hibernate: cache of collections

  1. ad

    Hello,

    I will take your example to explain my problem. For example, i create in a transaction (transaction 1) a customer with an order :
    tx.begin();
    Customer c = new Customer();
    Order o = new Order();
    c.getOrders().add(o);
    tx.commit();

    Then i open a new transaction (transaction 2) to get the customer and the order.
    tx.begin();
    entityManager. find(c)..;
    c.getOrders() ; -> database call!!

    Then in another transaction (transaction 3) you did the same thing, and the collection is in the cache. But why isn’t it in the cache in the transaction 2 directly, as we created it in tranaction 1? Is it necessary to have asked it in transaction 2 to have it in transaction 3 or did i make a mistake?

  2. Eric J. Van der Velden

    How did you found out about

    lazy=”false”

    in ? Because otherwise the collection is not written into Ehcache, unless you interate over the collection.

Leave a Reply

Your email address will not be published. Required fields are marked *