Performance Zone is brought to you in partnership with:

Markus is a principal technology consultant working for msg systems ag in Germany. Markus is a software architect, developer and consultant. He also writes for IT magazines. Markus joined msg in 2002 and has been a member of the Center of Competence IT-Architecture for nine years. After that Markus moved on to the IT-Strategy and Architecture group. He works daily with customers and projects dealing with Enterprise level Java and infrastructures. This includes the Java platform and several Web-related technologies on a variety of platforms using products from different vendors. His main area of expertise are Java EE Servers. Markus is speaking at different conferences about his favorite topics. He is also part of the Java EE 7 expert group. Stay up to date with his activities visiting his blog ( Follow him on twitter @myfear. Markus is a DZone MVB and is not an employee of DZone and has posted 159 posts at DZone. You can read more from them at their website. View Full User Profile

High Performance JPA with GlassFish and Coherence - Part 3

  • submit to reddit

In this third part of my four part series I'll explain strategy number two of using Coherence with EclipseLink and GlassFish. This is all about using Coherence as Second Level Cache (L2) with EclipseLink.

General approach

This approach applies Coherence data grid to JPA applications that rely on database hosted data that cannot be entirely pre-loaded into a Coherence cache. Some reasons why it might not be able to pre-loaded include extremely complex queries that exceed the feature set of Coherence Filters, third party database updates that create stale caches, reliance on native SQL queries, stored procedures or triggers, and so on. This is not only an option for local L2 Caches but with additional configured Coherence instances on different nodes, you also get a cluster-wide JPA L2 Cache.


As with many Caches, this is a read-mostly optimization. Primary key queries attempt to get entities first from Coherence and, if unsuccessful, will query the database, updating Coherence with query results. Non-primary key queries are executed against the database and the results checked against Coherence to avoid object construction costs for cached entities. Newly queried entities are put into Coherence. Write operations update the database and, if successfully committed, updated entities are put into Coherence. This approach is called "Grid Cache" in the Coherence documentation.

Move it into practice

Start with the previous blog-post and prepare your environment, if you have not already done so. There is a single thing, you need to change. Go back to GlassFish 3.0.1 / EclipseLink 2.0.1 for this scenario as there is a problem with the CacheKey.getKey() method. The 2.0.1 returns a Vector, the 2.2.0 simply returns an Object. Seeing the new Oracle GlassFish Server 3.1 having support for ActiveCache, I expect this to be fixed with the 3.7 Coherence release. But until than, you have to stick to the old GF or EclipseLink.

Anyway, lets create a new web project with your favorite IDE (e.g. GridCacheExample). Add the required libraries (coherence.jar, toplink-grid.jar and the eclipselink.jar). Now let's create our entity class and add the extra @CacheInterceptor annotation to it:

import oracle.eclipselink.coherence.integrated.cache.CoherenceInterceptor;
import org.eclipse.persistence.annotations.CacheInterceptor;

@CacheInterceptor(value = CoherenceInterceptor.class)
public class Employee implements Serializable {

Don't forget to add the @GeneratedValue(strategy= GenerationType.SEQUENCE) as this is needed in opposite to the last example. After this is done, you have to add the coherence configuration to your WEB-INF/classes folder. You can start from the tutorial (Example 2). (be careful, there is a typo in it ... a dublicate </backing-map-scheme> tag). Configure your persistence.xml as you would do with a normal JPA based application.

<persistence-unit name="GridCacheExamplePU" transaction-type="JTA">
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="FINE" />

That's it basically. Now you can test your new L2 cache. A simple servlet should do the trick:

public class InsertServletPart3 extends HttpServlet {
@PersistenceUnit(unitName = "GridCacheExamplePU")
EntityManagerFactory emf;
UserTransaction tx;

EntityManager em = emf.createEntityManager();
// some loop magic
Employee employee = new Employee();
// some loop magic end

If you watch the log, you can see something like this:

 bind => [Eisele, Markus]
FEIN: Coherence(Employee)::Put: 1 value: net.eisele.coherence.entities.Employee[ id=1 ]

Which basically tells you, that the actual database insert is carried out by EclipseLink as you are used to. After that, you can see, that the Employee object is put to the Coherence Cache named Employee with the PK as it's key.

If you now issue a query against the database

em.createQuery("select e from Employee e where e.lastName = :lastName").setParameter("lastName", "Eisele").getResultList()

you see the following:

 bind => [Eisele]
FEIN: Coherence(Employee)::Get: 1 result: net.eisele.coherence.entities.Employee[ id=1 ]
FEIN: Coherence(Employee)::Put: 1 value: net.eisele.coherence.entities.Employee[ id=1 ]

Which tells you, that the query itself is issued against the database but the results checked against Coherence to avoid object construction already for cached entities. Newly queried entities are put into Coherence. If you issue a simple PK query:


em.find(Employee.class, 1);

the output changes to:

FEIN: Coherence(Employee)::Get: 1 result: net.eisele.coherence.entities.Employee[ id=1 ]

and you don't see any db query at all. That's it :) Your cache works! Thanks for reading. Stay tuned for the next part!

Further Reading

OTN How-To: Using Coherence as a Shared L2 Cache

Integration Guide for Oracle TopLink with Coherence Gird 11g Release 1 (11.1.1)



Published at DZone with permission of Markus Eisele, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)