Performance Zone is brought to you in partnership with:

Markus is a Developer Advocate at Red Hat and focuses on JBoss Middleware. He is working with Java EE servers from different vendors since more than 14 years and talks about his favorite topics around Java EE on conferences all over the world. He has been a principle consultant and worked with different customers on all kinds of Java EE related applications and solutions. Beside that he has always been a prolific blogger, writer and tech editor for different Java EE related books. He is the Java Community leader of the German DOAG e.V. and it's representative on the iJUG e.V. As a Java Champion and former ACE Director he is well known in the community. Markus is a DZone MVB and is not an employee of DZone and has posted 195 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

03.07.2011
| 6204 views |
  • 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.

Details

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;
...

@Entity
@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">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/coherence</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="FINE" />
</properties>
</persistence-unit>

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;
@Resource
UserTransaction tx;
...

EntityManager em = emf.createEntityManager();
tx.begin();
// some loop magic
Employee employee = new Employee();
employee.setFirstName("Markus");
employee.setLastName("Eisele");
em.persist(employee);
// some loop magic end
tx.commit();
em.close();

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

FEIN: INSERT INTO EMPLOYEE (LASTNAME, FIRSTNAME) VALUES (?, ?)
 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:

FEIN: SELECT ID, LASTNAME, FIRSTNAME FROM EMPLOYEE WHERE (LASTNAME = ?)
 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)

 

From http://blog.eisele.net/2011/03/high-performance-jpa-with-glassfish-and.html

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.)